android-fragments 通过不同的片段复制菜单项

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

在OnCreateOptionsMenu()被标记为弃用后,我已经设法使用了发布说明www.example.com中的新APIhttps://developer.android.com/jetpack/androidx/releases/activity#1.4.0-alpha01在我的应用中,用户可以通过bottomNavigation切换片段。据我所知,在每个片段中,我都实现了MenuProvider(有无生命周期,对结果无关紧要)。但现在在每个片段中,用户都拥有所有menuInflater中的所有项。下面是实现代码
片段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这样工作,或者也许我犯了一个错误。非常感谢帮助:)

z0qdvdin

z0qdvdin1#

我今天也遇到了这个问题。所以不确定你是否有intellisense,但是看看一些Menu接口方法。我在Kotlin中使用了hasVisibleItems()方法,以便只在菜单不存在的情况下膨胀菜单。Java也有这个方法;您的代码片段增加了条件:

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。在你的碎片里;它将沿着如下:

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

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

trnvg8h3

trnvg8h32#

我也遇到了类似的问题。在我的应用程序中,我使用了片段和导航。我发现的问题是,在导航过程中,片段从不调用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
            }

        }
    }
}

正如您在我的代码中所看到的,只有当当前导航状态是与片段相关联的状态时,我才添加菜单项,否则,我什么也不做。
为了避免菜单持久化,在添加项目之前,我清除了菜单。
我希望这能帮上忙。

相关问题