You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为嵌套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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:40:13