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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 09:49:09