在Fragment自定义Toolbar中添加SearchView并实现页面间显隐
问题分析与解决方案
核心崩溃原因
- Navigation Component的
setupActionBarWithNavController与Fragment内部的setSupportActionBar(toolbar)存在ActionBar管理冲突 - XML布局中Toolbar内部直接放置了
SearchView,同时又通过Options Menu加载同名ID的SearchView,导致视图查找/类型转换错误 - 未正确处理Fragment切换时的Toolbar显示/隐藏逻辑
步骤1:修正MainActivity导航栏管理
移除Navigation对ActionBar的自动管理,改为手动处理返回逻辑,避免与Fragment的Toolbar冲突:
class MainActivity : AppCompatActivity() { private lateinit var navController: NavController private lateinit var viewModel: NotesViewModel private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) viewModel = ViewModelProvider( this, ViewModelProvider.AndroidViewModelFactory.getInstance(application) )[NotesViewModel::class.java] val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment navController = navHostFragment.navController // 监听导航目的地变化,控制Toolbar显示状态 navController.addOnDestinationChangedListener { _, destination, _ -> val homeFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView) ?.childFragmentManager?.fragments?.firstOrNull() as? HomeNoteFragment homeFragment?.let { when(destination.id) { R.id.homeNoteFragment -> it.binding.abLayout.visibility = View.VISIBLE R.id.createNotesFragment, R.id.editNotesFragment -> it.binding.abLayout.visibility = View.GONE } } } } // 手动处理导航返回按钮 override fun onSupportNavigateUp(): Boolean { return navController.navigateUp() || super.onSupportNavigateUp() } }
步骤2:重构HomeNoteFragment的Toolbar与SearchView逻辑
2.1 修改XML布局
移除Toolbar内部的SearchView标签,避免ID冲突:
<androidx.appcompat.widget.Toolbar android:id="@+id/toolBarHomeNoteFragment" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:title="Notes" app:titleTextColor="@color/white" app:layout_scrollFlags="scroll|enterAlways" />
2.2 修改Fragment代码
直接使用Fragment自身的Toolbar加载菜单,不干扰Activity的ActionBar:
class HomeNoteFragment : Fragment(R.layout.fragment_home_note) { private lateinit var binding: FragmentHomeNoteBinding private val viewModel: NotesViewModel by viewModels() private lateinit var notesAdapter: NotesAdapter private lateinit var navController: NavController override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding = FragmentHomeNoteBinding.bind(view) navController = Navigation.findNavController(view) // 用Fragment自己的Toolbar加载菜单 binding.toolBarHomeNoteFragment.apply { inflateMenu(R.menu.search_menu) setupSearchView(this.menu) } setUpRecyclerView() binding.llFabAddNote.setOnClickListener { navController.navigate(R.id.action_homeNoteFragment_to_createNotesFragment) } binding.fabAddNote.setOnClickListener { navController.navigate(R.id.action_homeNoteFragment_to_createNotesFragment) } } private fun setupSearchView(menu: Menu) { val searchItem = menu.findItem(R.id.search_view) val searchView = searchItem.actionView as SearchView searchView.queryHint = "Search Notes..." searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { override fun onMenuItemActionExpand(item: MenuItem): Boolean { return true } override fun onMenuItemActionCollapse(item: MenuItem): Boolean { notesAdapter.filterList("") // 折叠时恢复全部笔记 return true } }) searchView.setIconifiedByDefault(true) searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(nextText: String?): Boolean { return false } override fun onQueryTextChange(newText: String?): Boolean { newText?.let { notesAdapter.filterList(it) } return true } }) } private fun setUpRecyclerView() { binding.rvNotesList.layoutManager = StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL) notesAdapter = NotesAdapter(requireContext()) binding.rvNotesList.adapter = notesAdapter viewModel.allNotes.observe(viewLifecycleOwner) { list -> if (list.isEmpty()) { binding.noData.visibility = View.VISIBLE } else { binding.noData.visibility = View.GONE notesAdapter.updateList(list) } } } }
步骤3:确保Search Menu配置正确
res/menu/search_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/search_view" android:icon="@drawable/ic_search" android:title="Search" app:actionViewClass="androidx.appcompat.widget.SearchView" app:showAsAction="collapseActionView|ifRoom" /> </menu>
内容的提问来源于stack exchange,提问作者Shagun
相关产品推荐
相关产品推荐

