如何在Navigation Component架构的特定Fragment中实现专属SearchView
实现仅在HomeFragment显示SearchView并完成搜索功能
嘿,我来帮你搞定这个需求!结合你现有的Navigation Component架构(单Activity+多Fragment+导航抽屉),咱们分两步走:让SearchView只在HomeFragment显示,以及实现书籍列表的搜索过滤。
步骤1:控制SearchView的显示/隐藏(仅在HomeFragment可见)
因为Navigation Component会管理Fragment的切换,我们需要在宿主Activity中监听导航目的地的变化,动态控制Toolbar上的SearchView是否显示。
1.1 在宿主Activity(比如MainActivity)中配置Toolbar与导航监听
首先确保你的Activity布局里有Toolbar,然后在onCreate中完成以下配置:
public class MainActivity extends AppCompatActivity { private Toolbar toolbar; private NavController navController; private AppBarConfiguration appBarConfiguration; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); // 获取NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); // 监听导航目的地变化,控制SearchView显示 navController.addOnDestinationChangedListener((controller, destination, arguments) -> { // 替换成你的HomeFragment的目的地ID(从navigation.xml中获取) if (destination.getId() == R.id.homeFragment) { // 显示SearchView,可选隐藏标题腾空间 getSupportActionBar().setDisplayShowTitleEnabled(false); invalidateOptionsMenu(); // 触发OptionsMenu重建 } else { // 隐藏SearchView,恢复标题 getSupportActionBar().setDisplayShowTitleEnabled(true); invalidateOptionsMenu(); } }); // 配置导航抽屉 DrawerLayout drawer = findViewById(R.id.drawer_layout); NavigationView navigationView = findViewById(R.id.nav_view); appBarConfiguration = new AppBarConfiguration.Builder( R.id.homeFragment, R.id.otherFragment1, R.id.otherFragment2) .setOpenableLayout(drawer) .build(); NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration); NavigationUI.setupWithNavController(navigationView, navController); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_menu, menu); // 获取SearchView MenuItem searchItem = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) searchItem.getActionView(); // 根据当前目的地决定是否显示SearchView if (navController.getCurrentDestination() != null && navController.getCurrentDestination().getId() == R.id.homeFragment) { searchItem.setVisible(true); } else { searchItem.setVisible(false); } // 将SearchView的监听传递给HomeFragment HomeFragment currentFragment = (HomeFragment) getSupportFragmentManager() .findFragmentById(R.id.nav_host_fragment) .getChildFragmentManager() .getPrimaryNavigationFragment(); if (currentFragment != null) { currentFragment.setupSearchView(searchView); } return true; } @Override public boolean onSupportNavigateUp() { return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp(); } }
1.2 创建菜单文件(res/menu/main_menu.xml)
添加SearchView的菜单项:
<?xml version="1.0" encoding="utf-8"?> <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="Search Books" android:icon="@drawable/ic_search" app:showAsAction="ifRoom|collapseActionView" app:actionViewClass="androidx.appcompat.widget.SearchView" /> </menu>
1.3 修改HomeFragment,启用OptionsMenu并接收SearchView
在HomeFragment中,首先要启用OptionsMenu,然后实现SearchView的监听:
public class HomeFragment extends Fragment { // ... 你的现有代码 ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 启用OptionsMenu,让Fragment能处理菜单逻辑 setHasOptionsMenu(true); // ... 你的现有初始化代码(navController、RecyclerView等) ... } // 新增方法:接收Activity传递的SearchView并设置监听 public void setupSearchView(SearchView searchView) { searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { // 提交搜索时的处理(可选) adapter.getFilter().filter(query); return true; } @Override public boolean onQueryTextChange(String newText) { // 实时过滤列表 adapter.getFilter().filter(newText); return true; } }); } @Override public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); // 这里无需重复inflate菜单,Activity已处理全局菜单逻辑 } // ... 你的现有代码 ... }
步骤2:完善Adapter的搜索过滤逻辑
你现有的BookAdapterHome已经实现了Filterable接口,但当前过滤条件是按BorrowerId匹配,这不符合搜索书籍的常规需求(用户通常会搜书名或作者),我们修改过滤逻辑:
public class BookAdapterHome extends RecyclerView.Adapter<BookAdapterHome.BookHolder> implements Filterable { // ... 你的现有代码 ... Filter bookFilter=new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { List<Book> filteredBook=new ArrayList<>(); if(constraint==null ||constraint.length()==0){ filteredBook.addAll(bookListFull); } else{ String filterPattern=constraint.toString().toLowerCase().trim(); // 修改过滤条件:匹配书名或作者(可根据需求调整) for(Book item:bookListFull){ if(item.getTitle().toLowerCase().contains(filterPattern) || item.getAuthor().toLowerCase().contains(filterPattern)){ filteredBook.add(item); } } } FilterResults results=new FilterResults(); results.values=filteredBook; return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { bookList.clear(); bookList.addAll((List)results.values); notifyDataSetChanged(); } }; // 新增方法:同步Firebase更新后的全量数据 public void updateFullList(List<Book> newList) { bookListFull.clear(); bookListFull.addAll(newList); } // ... 你的现有代码 ... }
然后在HomeFragment的PreparingAllData方法中,更新完bookList后同步全量数据:
private void PreparingAllData() { databaseReference.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { bookList.clear(); for (DataSnapshot singleBook : dataSnapshot.getChildren()) { Book book = singleBook.getValue(Book.class); bookList.add(book); } adapter.updateFullList(bookList); // 同步全量数据 adapter.notifyDataSetChanged(); } @Override public void onCancelled(@NonNull DatabaseError databaseError) { } }); }
关键注意点
- 确保
navigation.xml中HomeFragment的ID和代码中判断的R.id.homeFragment一致,别写错。 - 如果你希望进入HomeFragment时SearchView自动展开,可以在
setupSearchView里加上searchView.setIconified(false);。 - 全量数据同步很重要:Firebase数据更新后,要同步更新Adapter的
bookListFull,否则搜索会基于旧数据。
这样一来,就只有当用户停留在HomeFragment时,Toolbar上才会显示SearchView,并且输入内容时会实时过滤书籍列表啦!
内容的提问来源于stack exchange,提问作者Jakaria Masud
相关产品推荐
相关产品推荐

