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

在Fragment自定义Toolbar中添加SearchView并实现页面间显隐

问题分析与解决方案

核心崩溃原因

  1. Navigation Component的setupActionBarWithNavController与Fragment内部的setSupportActionBar(toolbar)存在ActionBar管理冲突
  2. XML布局中Toolbar内部直接放置了SearchView,同时又通过Options Menu加载同名ID的SearchView,导致视图查找/类型转换错误
  3. 未正确处理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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:27:01