android-fragments 隐藏Fragment中的菜单项,并在使用新菜单提供程序API弃用'setHasOptionsMenu'后在navback上再次显示它们

w80xi6nr  于 2022-11-13  发布在  Android
关注(0)|答案(2)|浏览(166)

大约一个月前,Android团队弃用了onCreateOptionsMenuonOptionsItemSelected,以及setHasOptionsItemMenu。不幸的是,这破坏了我所有的代码。
我的应用程序有很多片段,当用户导航到这些片段时,我总是确保菜单项会消失,并在导航回来时重新出现,使用以下代码:
第一个
这段代码运行得很好,而且非常简单。现在Android团队已经弃用了(为什么?)X1 M3 N1 X,我无法重新创建这段代码。
我理解用于膨胀菜单项和处理菜单项单击事件的新语法,尽管我无法弄清楚--我的一生都无法弄清楚--如何在片段中隐藏菜单,然后使用新的菜单提供程序API在导航回来时再次显示它。
以下是我尝试过的方法:

  • 导航到片段:*
if (supportFragmentManager.backStackEntryCount == 0) {
            supportFragmentManager.commit {
                replace(R.id.activityMain_primaryFragmentHost, NewProjectFragment.newInstance(mainSpotlight != null))
                addToBackStack(null)
            }
        }
  • ActivityFragment接口中的getRootMenuProvider函数:*
interface ActivityFragment {
    val title: String

    companion object {
        fun getRootMenuProvider() = object : MenuProvider {
            override fun onPrepareMenu(menu: Menu) {
                for (_menuItem in menu.children) {
                    _menuItem.isVisible = false
                }
            }

            override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
            }

            override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
                return false
            }
        }
    }
}
  • 使用getRootMenuProvider函数:*
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val menuHost: MenuHost = requireActivity()
        menuHost.addMenuProvider(ActivityFragment.getRootMenuProvider())
    }
  • MainActivity(尝试将菜单项还原到以前的状态):*
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
        for (_menu in menu.children) {
            _menu.isVisible = true
        }

        return super.onPrepareOptionsMenu(menu)
    }

    override fun onBackPressed() {
        super.onBackPressed()
        findViewById<BottomNavigationView>(R.id.activityMain_bottomNavigationView)?.visibility = View.VISIBLE
        invalidateOptionsMenu()
    }

这会隐藏片段中的项目,但在导航返回后,这些项目仍然保持隐藏状态,直到用户通过旋转屏幕或执行类似操作重新加载Activity。
如何使用新的菜单提供程序API* 隐藏片段中的菜单项,并在导航返回时重新显示 *?

xriantvc

xriantvc1#

短期

所有东西都“坏了”的原因是因为您假设menu.clear()和片段菜单调用的分派发生在Activity添加了自己的菜单项之后。片段现在在Activity调用super.onCreateOptionsMenu()super.onPrepareOptionsMenu()时经历菜单调用的分派,所以您可以通过将其作为重写调用的最后而不是第一次调用来“修复”您的问题。

长期

事实上,你做错了很多:由Activity控制的全局菜单是一个共享资源,任何单独的片段都不应该手动清除整个菜单。这会破坏Activity菜单项、子片段菜单项以及其他片段的菜单项。只有使某些菜单项膨胀的组件才应该接触这些特定的菜单项。
因此,要解决您的问题,您应该遵循Activity 1.4.0-alpha 01发行说明(该发行版将MenuHostMenuProvider集成添加到Activity层:
AndroidX ComponentActivity [及其FragmentActivityAppCompatActivity的子类]现在实现了MenuHost接口。这允许任何组件通过向Activity添加MenuProvider示例来向ActionBar添加菜单项。每个MenuProvider都可以选择添加一个生命周期,该生命周期将根据Lifecycle状态和句柄自动控制这些菜单项的可见性当Lifecycle被销毁时,删除MenuProvider
他们接着展示了它在片段中的用法:

/**
  * Using the addMenuProvider() API in a Fragment
  **/
ExampleFragment : Fragment(R.layout.fragment_example) {

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    // The usage of an interface lets you inject your own implementation
    val menuHost: MenuHost = requireActivity()
  
    // Add menu items without using the Fragment Menu APIs
    // Note how we can tie the MenuProvider to the viewLifecycleOwner
    // and an optional Lifecycle.State (here, RESUMED) to indicate when
    // the menu should be visible
    menuHost.addMenuProvider(object : MenuProvider {
      override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
        // Add menu items here
        menuInflater.inflate(R.menu.example_menu, menu)
      }

      override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
        // Handle the menu selection
        return true
      }
    }, viewLifecycleOwner, Lifecycle.State.RESUMED)
  }

这特别说明了三件事:
1.一个MenuProvider应该只接触它的菜单项。你永远不应该“清除所有菜单项”或者任何影响另一个组件菜单项的操作。
1.通过使用生命周期调用addMenuProvider(在本例中,是Fragment视图的生命周期--即仅当Fragment视图在屏幕上时才存在的生命周期),那么当Fragment视图被销毁时,您自动隐藏菜单项(当您的replace调用发生时),并自动在您的片段视图重新出现时(即,当回栈弹出时)重新显示。
1.控制Lifecycle和菜单项可见性的片段本身应该是创建和处理自己的菜单项的片段。您的Activity(可以添加自己的MenuProvider,如另一个示例所示)应该只添加Activity的整个生命周期中存在的菜单项(在所有片段上可见的项)。

6tdlim6h

6tdlim6h2#

我有一些片段不需要菜单。因此我清除了菜单。现在似乎没有办法满足这个要求。

相关问题