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

Android MenuProvider的onMenuItemSelected()未触发问题求助

Fragment中SearchView点击无回调触发

我需要在多个Fragment中实现Toolbar内嵌的SearchView,需求是点击Toolbar末端的搜索按钮展开搜索栏。当前的实现步骤如下:

  • 创建仅包含搜索项的search_menu.xml菜单文件
  • 创建以androidx.appcompat.widget.SearchView为根布局的layout_search.xml
  • 在Fragment中实现MenuProvider接口

但测试时遇到问题:点击搜索按钮后SearchView能正常显示,但onMenuItemSelected()方法内的逻辑完全没有被调用。我还尝试过在Fragment中单独放置Toolbar、加载菜单并设置binding.toolbar.setOnMenuItemClickListener,同样没有回调触发。

为了复现问题,我基于底部导航栏模板新建项目,在自动生成的Fragment中实现MenuProvider,通过日志测试发现没有相关输出。以下是代码示例:

代码示例

HomeFragment.kt

class HomeFragment : Fragment(), MenuProvider {

    private var _binding: FragmentHomeBinding? = null


    private val binding get() = _binding!!
    private val queryConsumer: (String) -> Unit = { Log.i("HOME_FRAGMENT", "CONSUMED QUERY: $it") }
    private var searchView: SearchView? = null
    private val onBackPressed: OnBackPressedCallback = object : OnBackPressedCallback(false) {
        override fun handleOnBackPressed() {
            clearSearch()
            closeSearch()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        requireActivity().onBackPressedDispatcher.addCallback(onBackPressed)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val homeViewModel =
            ViewModelProvider(this)[HomeViewModel::class.java]

        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        val root: View = binding.root

        val textView: TextView = binding.textHome
        homeViewModel.text.observe(viewLifecycleOwner) {
            textView.text = it
        }
        return root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val menuHost = requireActivity() as MenuHost
        menuHost.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
        menuInflater.inflate(R.menu.search_menu, menu)
    }

    override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) {
        R.id.search_menu_item -> {
            Log.i("HOME_FRAGMENT", "NOW IN SEARCH MENU ITEM BRANCH")

            searchView = menuItem.actionView as? SearchView

            searchView?.run {
                queryHint = "hint"
                maxWidth = Int.MAX_VALUE

                setOnClickListener {
                    onSearchOpened()
                }

                setOnCloseListener {
                    onSearchClosed()

                    queryConsumer.invoke("")

                    return@setOnCloseListener false
                }

                setOnQueryTextListener(object : SearchView.OnQueryTextListener {
                    override fun onQueryTextSubmit(query: String): Boolean {
                        queryConsumer.invoke(query)
                        return true
                    }

                    override fun onQueryTextChange(newText: String): Boolean {
                        queryConsumer.invoke(newText)
                        return true
                    }
                })
            }

            true
        }
        else -> {
            Log.i("HOME_FRAGMENT", "NOW IN ELSE BRANCH")
            false
        }
    }

    fun clearSearch() {
        searchView?.setQuery("", true)
    }

    fun closeSearch() {
        searchView?.isIconified = true
    }

    fun onSearchClosed() {
        onBackPressed.isEnabled = false
    }

    fun onSearchOpened() {
        onBackPressed.isEnabled = true
    }
}

layout_search.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.SearchView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/search"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

</androidx.appcompat.widget.SearchView>

search_menu.xml

<?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_menu_item"
        android:contentDescription="@string/search_menu_title"
        android:icon="?android:attr/actionModeWebSearchDrawable"
        android:title="@string/search_menu_title"
        app:actionViewClass="androidx.appcompat.widget.SearchView"
        app:showAsAction="always" />
</menu>

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val navView: BottomNavigationView = binding.navView

        val navController = findNavController(R.id.nav_host_fragment_activity_main)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)


    }
}

内容的提问来源于stack exchange,提问作者UnDan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:03:21