迁移至addMenuProvider后,切换Fragment时ActionBar菜单图标闪烁如何解决?
核心思路
通过同步控制菜单的移除与添加时机,避免新旧Fragment的菜单在切换时短暂共存。
具体方案
1. 持有MenuProvider实例引用
不在Fragment内匿名创建MenuProvider,而是保留实例引用,方便主动管控:
class FirstFragment : Fragment() { private lateinit var menuProvider: MenuProvider override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) menuProvider = object : MenuProvider { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { menuInflater.inflate(R.menu.menu_first, menu) } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { return false } } requireActivity().addMenuProvider(menuProvider, viewLifecycleOwner) } }
2. 在Fragment切换前主动清空菜单
在宿主Activity的BottomNavigationView切换监听中,先清空ActionBar现有菜单,再执行Fragment切换:
// 宿主Activity中设置底部导航监听 binding.bottomNav.setOnItemSelectedListener { item -> // 用空菜单覆盖现有菜单,快速清空 requireActivity().menuInflater.inflate(R.menu.empty_menu, binding.toolbar.menu) // 执行Fragment切换逻辑 when(item.itemId) { R.id.nav_first -> { supportFragmentManager.beginTransaction() .replace(R.id.nav_host_fragment, FirstFragment()) .commit() true } R.id.nav_second -> { supportFragmentManager.beginTransaction() .replace(R.id.nav_host_fragment, SecondFragment()) .commit() true } else -> false } }
注:empty_menu是一个不含任何菜单项的空菜单资源文件
3. 延迟新菜单的加载时机
添加MenuProvider时指定Lifecycle.Event.ON_START生命周期事件,确保旧Fragment的菜单已完成移除后,再加载新菜单:
requireActivity().addMenuProvider(menuProvider, viewLifecycleOwner, Lifecycle.Event.ON_START)
4. 在Fragment销毁时强制清理菜单
在Fragment的onDestroyView中主动移除MenuProvider并触发菜单重绘:
override fun onDestroyView() { super.onDestroyView() requireActivity().removeMenuProvider(menuProvider) requireActivity().invalidateOptionsMenu() }
原理说明
旧版setHasOptionsMenu()基于Fragment生命周期同步更新菜单,而新的MenuProvider采用异步回调机制,导致切换时旧菜单移除与新菜单添加存在时间差。通过主动清空菜单、延迟新菜单加载、手动触发刷新这几个步骤,可消除菜单闪烁现象。
内容的提问来源于stack exchange,提问作者tenuki
相关产品推荐
相关产品推荐

