如何为嵌套RecyclerView中的全部图书添加带自定义Adapter的SearchView
给动态分类图书应用添加带自定义Adapter的SearchView方案
嘿,我刚好做过类似的需求,给你梳理下适配这种动态分类+横向图书列表场景的具体步骤:
1. 先整合全局图书数据源
你的图书是分散在各个分类的横向RecyclerView里的,首先得把所有用户可访问的图书收集到一个**全局的List<Book>**里,这样搜索时不用遍历每个分类的列表,效率更高:
// 在BrowseBooksActivity里定义全局变量 private List<Book> allBooksList = new ArrayList<>(); // 加载完所有分类和对应图书后,把每个分类的图书添加到全局列表 for (BookCategory category : categoryList) { allBooksList.addAll(category.getBookList()); }
2. 添加SearchView到界面
通常我们会把SearchView放到Toolbar里,更符合Material Design风格:
2.1 修改menu资源(比如res/menu/browse_menu.xml)
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/action_search" android:title="搜索图书" android:icon="@drawable/ic_search" app:showAsAction="ifRoom|collapseActionView" app:actionViewClass="androidx.appcompat.widget.SearchView" /> </menu>
2.2 在Activity里加载menu并配置SearchView
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.browse_menu, menu); MenuItem searchItem = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) searchItem.getActionView(); // 配置SearchView基础属性 searchView.setQueryHint("输入图书名搜索"); searchView.setMaxWidth(Integer.MAX_VALUE); // 让搜索框占满宽度 // 处理搜索文本变化 searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { // 提交搜索时过滤并展示结果 filterBooks(query); searchView.clearFocus(); // 收起软键盘 return true; } @Override public boolean onQueryTextChange(String newText) { // 文本实时变化时动态过滤 filterBooks(newText); return true; } }); // 监听SearchView展开/收起,切换界面状态 searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { // 展开时隐藏原分类列表,显示搜索结果列表 mainCategoryRecyclerView.setVisibility(View.GONE); searchResultRecyclerView.setVisibility(View.VISIBLE); return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { // 收起时恢复原分类界面 mainCategoryRecyclerView.setVisibility(View.VISIBLE); searchResultRecyclerView.setVisibility(View.GONE); return true; } }); return super.onCreateOptionsMenu(menu); }
3. 自定义搜索结果的Adapter
你需要一个专门的RecyclerView Adapter来展示搜索结果(和原分类+横向列表布局不同),比如BookSearchResultAdapter:
public class BookSearchResultAdapter extends RecyclerView.Adapter<BookSearchResultAdapter.BookViewHolder> { private List<Book> filteredBooks; private OnBookClickListener listener; public interface OnBookClickListener { void onBookClick(Book book); } public BookSearchResultAdapter(List<Book> books, OnBookClickListener listener) { this.filteredBooks = books; this.listener = listener; } // 更新过滤后的图书列表 public void updateList(List<Book> newList) { filteredBooks = newList; notifyDataSetChanged(); } @NonNull @Override public BookViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_book_search_result, parent, false); return new BookViewHolder(view); } @Override public void onBindViewHolder(@NonNull BookViewHolder holder, int position) { Book book = filteredBooks.get(position); holder.bookTitle.setText(book.getTitle()); holder.bookAuthor.setText(book.getAuthor()); // 加载图书封面等其他信息... holder.itemView.setOnClickListener(v -> listener.onBookClick(book)); } @Override public int getItemCount() { return filteredBooks.size(); } static class BookViewHolder extends RecyclerView.ViewHolder { TextView bookTitle; TextView bookAuthor; ImageView bookCover; public BookViewHolder(@NonNull View itemView) { super(itemView); bookTitle = itemView.findViewById(R.id.tv_book_title); bookAuthor = itemView.findViewById(R.id.tv_book_author); bookCover = itemView.findViewById(R.id.iv_book_cover); } } }
对应的布局item_book_search_result.xml可以设计成竖向条目,展示封面、标题、作者等你需要的信息。
4. 实现过滤逻辑
在Activity里实现filterBooks方法,根据输入文本过滤全局图书列表:
private BookSearchResultAdapter searchResultAdapter; private RecyclerView searchResultRecyclerView; // 在onCreate里初始化搜索结果RecyclerView @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_browse_books); // 初始化原分类列表的RecyclerView... // 初始化搜索结果RecyclerView searchResultRecyclerView = findViewById(R.id.rv_search_results); searchResultRecyclerView.setLayoutManager(new LinearLayoutManager(this)); searchResultAdapter = new BookSearchResultAdapter(new ArrayList<>(), book -> { // 处理图书点击事件,比如跳转到详情页 Intent intent = new Intent(this, BookDetailActivity.class); intent.putExtra("BOOK_DATA", book); startActivity(intent); }); searchResultRecyclerView.setAdapter(searchResultAdapter); searchResultRecyclerView.setVisibility(View.GONE); // 默认隐藏 } private void filterBooks(String query) { List<Book> filteredList = new ArrayList<>(); if (TextUtils.isEmpty(query)) { // 搜索文本为空时展示所有图书 filteredList.addAll(allBooksList); } else { String lowerCaseQuery = query.toLowerCase(); for (Book book : allBooksList) { // 按书名、作者等字段匹配,可根据需求扩展匹配规则 if (book.getTitle().toLowerCase().contains(lowerCaseQuery) || book.getAuthor().toLowerCase().contains(lowerCaseQuery)) { filteredList.add(book); } } } // 更新搜索结果Adapter searchResultAdapter.updateList(filteredList); }
5. (可选)自定义SearchView的下拉提示Adapter
如果你不想用系统默认的搜索提示样式,想自定义下拉条目布局,可以给SearchView设置自定义的SuggestionsAdapter:
// 在配置SearchView的代码里添加 searchView.setSuggestionsAdapter(new CustomSearchSuggestionAdapter(this, allBooksList)); // 自定义SuggestionsAdapter示例 public class CustomSearchSuggestionAdapter extends CursorAdapter { private List<Book> bookList; private LayoutInflater inflater; public CustomSearchSuggestionAdapter(Context context, List<Book> books) { super(context, null, 0); this.bookList = books; this.inflater = LayoutInflater.from(context); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return inflater.inflate(R.layout.item_search_suggestion, parent, false); } @Override public void bindView(View view, Context context, Cursor cursor) { Book book = bookList.get(cursor.getPosition()); TextView suggestionText = view.findViewById(R.id.tv_suggestion); suggestionText.setText(book.getTitle()); } // 重写runQueryOnBackgroundThread处理搜索文本,生成自定义Cursor @Override public Cursor runQueryOnBackgroundThread(CharSequence constraint) { MatrixCursor cursor = new MatrixCursor(new String[]{"_id", "title"}); if (constraint != null) { String query = constraint.toString().toLowerCase(); for (int i = 0; i < bookList.size(); i++) { Book book = bookList.get(i); if (book.getTitle().toLowerCase().contains(query)) { cursor.addRow(new Object[]{i, book.getTitle()}); } } } return cursor; } }
这个自定义提示Adapter的实现稍复杂,如果你的需求只是搜索后展示结果,前面的步骤已经足够;如果需要更个性化的搜索提示,再考虑这一步。
最后提醒:如果你的图书是动态分页加载的,记得在加载更多图书时同步更新allBooksList,这样搜索结果才会包含最新的图书。
内容的提问来源于stack exchange,提问作者Zim
相关产品推荐
相关产品推荐

