kotlin 选择MenuItem时,Android MenuProvider不会调用onMenuItemSelected()

ewm0tg9j  于 2023-04-12  发布在  Kotlin
关注(0)|答案(1)|浏览(178)

在我的工作项目中,我们需要在几个Fragments中使用SearchView。搜索栏本身必须放置在Toolbar中,并通过单击Toolbarsee the image)末尾的搜索按钮打开。因此,我通过以下方式实现了这样的行为:

  • 添加只包含搜索项的 * menu.xml * 菜单文件;
  • 添加只包含androidx.appcompat.widget.SearchViewlayout_search.xml 布局文件作为根视图;
  • 在我的片段中实现MenuProvider接口。

然后,当我试图测试它是否按预期工作时,我发现**onMenuItemSelected()方法中编写的所有内容都从未被调用**。我的意思是,当单击工具栏中的搜索按钮时,搜索栏会像预期的那样出现在工具栏中,但系统不会调用我的侦听器来处理菜单项选择。
我只是不明白为什么菜单项选择回调没有被调用。我尝试了另一种方法来处理工具栏的菜单和它的项选择(例如,将工具栏放在我的片段中,膨胀菜单,然后用所需的处理程序设置binding.toolbar.setOnMenuItemClickListener),但它也导致了同样的结局-项选择回调根本不起作用。

***我希望有人曾经遇到过同样的问题,并找到了解决方案,因为我已经浪费了3天时间试图让项目选择回调工作,现在我感到被难住了。

为了重现这个问题,我创建了一个带有底部导航栏模板的新项目,添加了资源,并在自动生成的片段中实现了MenuProvider接口。为了测试项目选择回调是否被调用,我使用了logger,我的日志消息都没有出现在logcat中。代码示例如下:

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
    }
}

布局_搜索.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>

搜索菜单.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)

    }
}
jyztefdp

jyztefdp1#

问题隐藏在菜单 .xml 文件中...我只是随机地(从绝望中)将属性app:showAsAction的值从always更改为ifRoom|collapseActionView,所有回调(来自MenuProvideronMenuItemSelected和来自工具栏的setOnMenuItemClickListener)都开始工作!

相关问题