通过不同片段复制菜单项



在OnCreateOptionsMenu((被标记为不推荐使用之后,我成功地使用了发行说明中的新APIhttps://developer.android.com/jetpack/androidx/releases/activity#1.4.0-alpha01在我的应用程序中,用户可以通过底部导航切换碎片。根据我对文档的理解,在每个Fragment中,我都实现了MenuProvider(无论是否使用Lifecycle,结果都无关紧要(。但现在,在每个Fragment中,用户都拥有所有菜单充气器中的所有项目。有实现的代码

片段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会这样工作,或者我可能犯了一个错误。非常感谢您的帮助:(

我今天也遇到了这个问题。因此,不确定您是否具有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。我相信Java;在你的碎片里;它将沿着以下路线:

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

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

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

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

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

我希望这能有所帮助。

最新更新