【问题标题】:Duplicating menu items via different Fragments通过不同的片段复制菜单项
【发布时间】:2022-10-17 16:57:43
【问题描述】:

在 OnCreateOptionsMenu() 标记为已弃用后,我设法使用了来自发行说明 https://developer.android.com/jetpack/androidx/releases/activity#1.4.0-alpha01 的新 API 在我的应用程序中,用户可以通过底部导航切换片段。 据我了解文档,在每个片段中我都实现了 MenuProvider(有或没有生命周期,对结果无关紧要)。但是现在在每个 Fragment 用户中都有来自所有 menuInflaters 的所有项目。 有实现代码

片段A

@Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        SetMainParams();
        fragment = inflater.inflate( R.layout.fragment_A, container, false );

        addMenu();

        return fragment;
    }

    private void addMenu()
    {
        MenuProvider menuProvider = new MenuProvider()
        {
            @Override
            public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
            {
                menuInflater.inflate(R.menu.menu_fragment_A, menu);
            }

            @Override
            public boolean onMenuItemSelected(@NonNull MenuItem menuItem)
            {
                if( menuItem.getItemId() == R.id.filters_prev )
                    filtersPrevious();
                else if( menuItem.getItemId() == R.id.filters )
                    showFilters();
                else
                    filtersNext();

                return false;
            }
        };

        requireActivity().addMenuProvider(menuProvider, getViewLifecycleOwner(), Lifecycle.State.RESUMED);
    }

片段 B

@Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        SetMainParams();
        binding = FragmentBBinding.inflate(inflater, container, false);
        fragment = binding.getRoot();
        init();

        addMenu();

        return fragment;
    }

    private void addMenu()
    {
        MenuProvider menuProvider = new MenuProvider()
        {
            @Override
            public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
            {
                menuInflater.inflate(R.menu.menu_fragment_B, menu);
                filtersMenu = menu.getItem(0);
            }

            @Override
            public boolean onMenuItemSelected(@NonNull MenuItem menuItem)
            {
                if( menuItem.getItemId() == R.id.filters )
                    loadFilters();

                return false;
            }
        };

        requireActivity().addMenuProvider(menuProvider, getViewLifecycleOwner(), Lifecycle.State.RESUMED);
    }

从底部导航切换

binding.bottomNav.setOnItemSelectedListener(item ->
        {
            int itemId = item.getItemId();

            if( itemId == R.id.A )
            {
                fm.beginTransaction().hide(active_fragment).show(A_fragment).commit();
                active_fragment = A_fragment;
                setWithElevation(false);
            }
            else if( itemId == R.id.B )
            {
                fm.beginTransaction().hide(active_fragment).show(B_fragment).commit();
                active_fragment = B_fragment;
                setWithElevation(true);
            }

            active_fragment.startFragment();
            active_fragment.setTitle();
            return true;
        });

        fm.beginTransaction().add( R.id.fl_content, A_fragment, "A_fragment" ).hide(A_fragment).commit();
        fm.beginTransaction().add( R.id.fl_content, B_fragment, "B_fragment" ).hide(B_fragment).commit();

有什么想法吗,为什么新的 API 会这样工作,或者我犯了一个错误。非常感谢您的帮助:)

【问题讨论】:

  • 你如何在底部导航的片段之间交换?
  • 内部活动使用 BottomNavigationView binding.bottomNav.setOnItemSelectedListener 然后 FragmentManager.beginTransaction
  • 请附上您的代码。 FragmentTransaction 可以做很多很多事情。
  • 我的错,对不起)用附加代码编辑我的问题
  • 您同时添加了所有片段,因此强制创建所有视图并将其始终保存在内存中(根据the docs,隐藏和显示对片段的生命周期没有任何作用)。这是您使用底部导航代码时的意图吗?

标签: android android-fragments


【解决方案1】:

我今天也遇到了这个问题。所以不确定你是否有智能感知,但看看一些Menu 接口方法。我在 Kotlin 中使用了 hasVisibleItems() 方法,仅在菜单不存在时才对它进行扩充。 Java也有方法;你的 sn-p 增加了条件:

MenuProvider menuProvider = new MenuProvider()
    {
         @Override
         public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
         {
             if (!menu.hasVisibleItem()) {  // only inflate if no items
                 menuInflater.inflate(R.menu.menu_fragment_A, menu);
             }
         }        
//...

Menu 还有许多其他方法可以帮助特定项目。
另一个好主意是使用MenuHost 接口来跟踪您的MenuProvider。我相信Java;在你的 Fragments 里面;这将是:

activityFragment = this.requireActivity();
Menuhost menuHost = (MenuHost) activityFragment;
menuHost.addMenuProvider(
    menuProvider,
    this.getViewLifecycleOwner(),
   State.RESUMED
);

然后可以使菜单提供程序无效等。

【讨论】:

    【解决方案2】:

    我有一个类似的问题。在我的应用程序中,我使用片段和导航。我发现的问题是,在导航过程中,片段从不调用onPause 事件。所以我所有的片段都在onViewCreated 方法中实现了这段代码:

    class HomeFragment : Fragment() {
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            ...
    
            val menuHost: MenuHost = requireActivity()
            menuHost.addMenuProvider(HomeMenuProvider(R.id.nav_main, findNavController(), this, authViewModel, homeViewModel), viewLifecycleOwner, Lifecycle.State.RESUMED)
        }
    

    HomeMenuProvider 是这样定义的:

    class HomeMenuProvider(private val currentNavId: Int) : MenuProvider {
        override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
            if ((navController.currentDestination?.id ?: -1L) == currentNavId) {
                menu.clear()
                menuInflater.inflate(R.menu.menu_main, menu)
            } 
        }
    
        override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
            return when (menuItem.itemId) {
                R.id.menu_action_login -> {
                    ...
                    true
                }
                else -> {
                    false
                }
    
            }
        }
    }
    

    正如您在我的代码中看到的那样,仅当当前导航状态是与片段关联的导航状态时,我才添加菜单项。否则,我什么也不做。

    为避免菜单持久性,在添加项目之前我清除菜单。

    我希望这有帮助。

    【讨论】:

      猜你喜欢
      • 2022-01-25
      • 1970-01-01
      • 2016-12-30
      • 1970-01-01
      • 2013-01-02
      • 2014-06-04
      • 2019-04-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多