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
相关产品推荐
相关产品推荐

