Duplicating menu items via different Fragments - android

After OnCreateOptionsMenu() marked as deprecated, I've managed to use new API from release notes https://developer.android.com/jetpack/androidx/releases/activity#1.4.0-alpha01
In my app user can switch Fragments via bottomNavigation.
As I understand docs, in each Fragment I've implemented MenuProvider(with or without Lifecycle, doesn't matter for result). But now in each Fragment user have all items from all menuInflaters.
There is the code of implementation
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);
}
FRAGMENT 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);
}
Switching from bottomNavigation
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();
Is there any ideas, why new API works like this, or maybe i've made a mistake. Thanks a lot for help :)

I also experienced this problem today. So not sure if you have intellisense, but look at some of the Menu interface methods. I used the hasVisibleItems() method in Kotlin to only inflate the menu if it does not exist. Java also has the method; your snippet augmented with conditional:
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 also has a bunch of other methods that may assist for specific items.
Also another good idea would be to use the MenuHost interface to keep track of your MenuProvider. I believe in Java; inside your Fragments; it would be along the lines of:
activityFragment = this.requireActivity();
Menuhost menuHost = (MenuHost) activityFragment;
menuHost.addMenuProvider(
menuProvider,
this.getViewLifecycleOwner(),
State.RESUMED
);
Menu providers can then be invalidated ect.

I've a similar problem. In my application, I'm using fragments and navigation. The problem I found is that during navigation, the fragment never call the onPause event. So all my fragment implements this code in onViewCreated method:
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)
}
The HomeMenuProvider is so defined:
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
}
}
}
}
As you can see in my code, I add menu items only if the current navigation status is the one associated with the fragment. Otherwise, simply I do nothing.
To avoid menu persistence, before add items I clear the menu.
I hope this helps.

Related

'setHasOptionsMenu(Boolean): Unit' is deprecated. Deprecated in Java

How do I declare a menu inside of Android fragment? The method that I had used previously is now deprecated.
Originally:
override fun onCreateView(...): View {
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
this.menu = menu
inflater.inflate(R.menu.menu, this.menu)
}
From the Developer documentation, this can be achieved by the following:
/**
* Using the addMenuProvider() API directly in your Activity
**/
class ExampleActivity : ComponentActivity(R.layout.activity_example) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Add menu items without overriding methods in the Activity
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
}
})
}
}
/**
* Using the addMenuProvider() API in a Fragment
**/
class 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 when (menuItem.itemId) {
R.id.menu_clear -> {
// clearCompletedTasks()
true
}
R.id.menu_refresh -> {
// loadTasks(true)
true
}
else -> false
}
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
}
Fragments setHasOptionsMenu deprecated, use setHasOptionsMenu
Expanding on what #joseph-wambura and #hammad-zafar-bawara said, you can also implement the interface in the fragment...
class MyFragment : Fragment(), MenuProvider {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Do stuff...
val menuHost: MenuHost = requireActivity()
menuHost.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
}
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.options, menu)
// Do stuff...
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Do stuff...
return false
}
}
In Kotlin, declaration for Activity, Fragment and PreferenceFragmentCompat
Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.main_menu, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return true
}
})
}
}
Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// The usage of an interface lets you inject your own implementation
val menuHost: MenuHost = requireActivity()
menuHost.addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
// Add menu items here
menuInflater.inflate(R.menu.main_menu, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return when (menuItem.itemId) {
R.id.action_menu1 -> {
// todo menu1
true
}
R.id.action_menu2 -> {
// todo menu2
true
}
else -> false
}
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
}
PreferenceFragmentCompat
val menuHost: MenuHost = requireHost() as MenuHost
//Same declaration with Fragment
Use MenuProvider interface
class FirstFragment : Fragment(), MenuProvider {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val menuHost: MenuHost = requireActivity()
menuHost.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
}
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
// Add menu items here
menuInflater.inflate(R.menu.second_menu, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return when (menuItem.itemId) {
R.id.menu_clear -> {
// Do stuff...
true
}
R.id.menu_refresh -> {
// Do stuff...
true
}
else -> false
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
}
JAVA CODE
Option menu in Activity
addMenuProvider(new MenuProvider() {
#Override
public void onCreateMenu(#NonNull Menu menu, #NonNull MenuInflater menuInflater) {
menuInflater.inflate(R.menu.bottom_nav_menu, menu);
// Add menu options here
}
#Override
public boolean onMenuItemSelected(#NonNull MenuItem menuItem) {
// Handle Menu Options Selection Here
return false;
}
});
Option menu in Fragment
requireActivity().addMenuProvider(new MenuProvider() {
#Override
public void onCreateMenu(#NonNull Menu menu, #NonNull MenuInflater menuInflater) {
menuInflater.inflate(R.menu.bottom_nav_menu, menu);
// Add option Menu Here
}
#Override
public boolean onMenuItemSelected(#NonNull MenuItem menuItem) {
return false;
// Handle option Menu Here
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED);
If you're using Jetpack NavigationUI then you need to setSupportActionBar(toolbar), otherwise the menu will not be present.
this helps me on onCreateView Method:
requireActivity().addMenuProvider(new MenuProvider() {
#Override
public void onCreateMenu(#NonNull Menu menu, #NonNull MenuInflater menuInflater) {
menuInflater.inflate(R.menu.bottom_nav_menu, menu);
// Add option Menu Here
}
#Override
public boolean onMenuItemSelected(#NonNull MenuItem menuItem) {
// Handle option Menu Here
return false;
}
}, getViewLifecycleOwner, Lifecycle.State.RESUMED);
I'm not sure why all answers recommend passing in Lifecycle.State.RESUME as the lifecycle state to the addMenuProvider call. This will make the menu disappear when the fragment is paused, which doesn't look great when the fragment is paused and still visible.
For example, showing a dialog as a result of tapping a menu item will make the menu disappear. It will re-appear when the dialog is dismissed.
For most cases, a better lifecycle state to pass in would be Lifecycle.State.CREATE, which will only remove the menu when the view is destroyed. This is also the default behaviour, so you can simply omit the lifecycle state.
in java for fragment i tried this . it works fine for me
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_example, container, false);
toolbar = (Toolbar)view.findViewById(R.id.toolbar_1);
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
MenuHost menuHost = requireActivity();
menuHost.addMenuProvider(new MenuProvider() {
#Override
public void onCreateMenu(#NonNull Menu menu, #NonNull MenuInflater menuInflater) {
menuInflater.inflate(R.menu.menu_search,menu);
}
#Override
public boolean onMenuItemSelected(#NonNull MenuItem menuItem) {
if (menuItem.getItemId() == R.id.search_friend){
Toast.makeText(getActivity(), "friends", Toast.LENGTH_SHORT).show();
return true;
}
else return false;
}
},getViewLifecycleOwner(), Lifecycle.State.RESUMED);
return view;
}

Android ReselectedListener for NavigationView

In BottomNavigationView it is possible to set:
bottomNavigationView.setOnNavigationItemReselectedListener(item -> {
// do nothing on reselection
});
However for NavigationView this is not available. What is a good equivalent?
UPDATE
Thanks to #ande I implemented the following:
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (currentMenuItemId == item.getItemId()) {
navDrawer.close();
return true;
}
currentMenuItemId = item.getItemId();
NavigationUI.onNavDestinationSelected(item, navController);
navDrawer.close();
return true;
}
That works well for if I only navigate via the menu items. (Btw, I just implemented the Listener in my Activity and added it from there, no need for an extra class)
However, when I press the back button then I will be able to press the menu button for the current destination, as the menu item did not update on onBackPressed().
Update 2
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
#Override
public void onDestinationChanged(#NonNull NavController controller, #NonNull NavDestination destination, #Nullable Bundle arguments) {
currentMenuItemId = destination.getId();
}
});
This solved it!
May be you can do like this ( I did quickly so may be it could be better!!)
class ReSelectedListener(val navigationViewCallBack: NavigationViewCallBack) : NavigationView.OnNavigationItemSelectedListener {
var newItemSelected : MenuItem? = null
override fun onNavigationItemSelected(item: MenuItem): Boolean {
if(newItemSelected != null){
if(newItemSelected!!.itemId == item.itemId){
navigationViewCallBack.setOnNavigationItemReselectedListener(item)
}
}
newItemSelected = item
return true
}
}
interface NavigationViewCallBack {
fun setOnNavigationItemReselectedListener(item: MenuItem)
}
And after
class YourFragment :Fragment(), NavigationViewCallBack
and
navigationView.setNavigationItemSelectedListener(ReSelectedListener(this))
and implements callback method in YourFragment:
override fun setOnNavigationItemReselectedListener(item: MenuItem) {
TODO("Not yet implemented")
}

Actionbar lost after rotation in dialog with toolbar

I'm implementing an app in Xamarin Android that contains a page that once you click on an actionbar button, you get a new dialog that contains a toolbar.
The simplified code is something like:
public class MyDialogFragment : MvxDialogFragment<MyDialogViewModel>
{
public MvxDialogFragment()
{
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
this.EnsureBindingContextIsSet(inflater);
var view = this.BindingInflate(Resource.Layout.dialog_view, null);
SetupToolbar(view);
return view;
}
private void SetupToolbar(View view)
{
Dialog.RequestWindowFeature((int)WindowFeatures.NoTitle);
Android.Support.V7.Widget.Toolbar toolbar = view.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.dialog_toolbar);
((AppCompatActivity)Activity).SetSupportActionBar(toolbar);
Android.Support.V7.App.ActionBar actionBar = ((AppCompatActivity)Activity).SupportActionBar;
actionBar.Title = null;
HasOptionsMenu = true;
}
public override void OnCreateOptionsMenu(IMenu menu, MenuInflater inflater)
{
menu.Clear();
inflater.Inflate(Resource.Menu.menu_dialog, menu);
base.OnCreateOptionsMenu(menu, inflater);
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
(...)
}
}
public override void OnPrepareOptionsMenu(IMenu menu)
{
(...)
base.OnPrepareOptionsMenu(menu);
}
The main workflow it works just fine, but there is a side effect when I rotate the screen while displaying the dialog.
If I do so, the actionbar buttons of the parent fragment(the one hosting the dialog), disappear till I recreate the view (ie: rotation).
Any ideas about how to solve this? I have tried several things like invalidate the parent menu after the dialog is closed, but it didn't work.
After some time investigating the problem, I don't think there is a way to make work 2 actionbars at the same time in a "native way".
My solution, in the end, was to manually handle the click events over the second actionbar.
public class MyDialogFragment : MvxDialogFragment<MyDialogViewModel>
{
public MvxDialogFragment()
{
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
this.EnsureBindingContextIsSet(inflater);
var view = this.BindingInflate(Resource.Layout.dialog_view, null);
SetupToolbar(view);
return view;
}
private void SetupToolbar(View view)
{
Dialog.RequestWindowFeature((int)WindowFeatures.NoTitle);
toolbar = view.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
toolbar.Title = null;
toolbar.InflateMenu(Resource.Menu.menu);
toolbar.MenuItemClick += HandlerMenuItemClick;
HasOptionsMenu = true;
}
public override bool HandlerMenuItemClick(object sender, Android.Support.V7.Widget.Toolbar.MenuItemClickEventArgs e)
{
switch (e.item.ItemId)
{
(...)
}
}
}
Hope it can helps anybody

Hide MenuItem in some Fragments

I using menu drawer which has more Fragments. In some Fragments I have menu item REFRESH but in some fragments I want hide this menu item (I don't want show menu but I don't want hide ActionBar).
I try add override onCreateOptionsMenu() to Fragment where I don't want show this menu item but I can not get it to work. I try many way see commented line in code. Does any idea where is problem? And last this menu item go to hide when I activate menu drawer when is called onPrepareOptionsMenu() in MainActivity but I need do this when I'm in Fragment.
Fragment where I want hide menu item REFRESH:
public class FindPeopleFragment extends Fragment {
public FindPeopleFragment(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_find_people, container, false);
//setHasOptionsMenu(false);
return rootView;
}
private Menu menu=null;
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
inflater.inflate(R.menu.main, menu);
this.menu=menu;
menu.findItem(R.id.refresh).setVisible(false);
getActivity().invalidateOptionsMenu();
//setHasOptionsMenu(false);
super.onCreateOptionsMenu(menu,inflater);
}
}
MainActivity where is defined MENU DRAWER:
//Slide menu item click listener
private class SlideMenuClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// display view for selected nav drawer item
displayView(position);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// toggle nav drawer on selecting action bar app icon/title
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
switch (item.getItemId()) {
case R.id.refresh:
Toast.makeText(this, "Refreshing data...", Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
// Called when invalidateOptionsMenu() is triggered
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// if nav drawer is opened, hide the action items
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.refresh).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
In the fragment where you want to hide the Item
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem item=menu.findItem(R.id.action_search);
if(item!=null)
item.setVisible(false);
}
and in onCreate() of your fragment
setHasOptionsMenu(true);
In the Fragment where you don't want to show any menu options, you need setHasOptionsMenu(false); in the onCreate(), like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(false);
}
However, the menu that is being shown that you would like to hide (REFRESH), belongs to MainActivity. That is why it is always shown. Since you want to control the menu at the Fragment level (and not show an Activity options menu), my suggestion is to delete the menu code from the Activity and implement it in your Fragment.
Activitys and Fragments can each have their own separate menus. See this link.
please try this
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.clear();
}
and put this on your fragmen's onCreate()
setHasOptionsMenu(true);
In Fragment Class
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
}
in Kotlin for those who needs it
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
menu.clear()
}
I used the code below for hiding menu items in a fragment where I don't want to use it.
Note: Please read comment
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
Fragment whichFragment=getVisibleFragment();//getVisible method return current visible fragment
String shareVisible=whichFragment.getClass().toString();
if(shareVisible.equals(AccFragment.class.toString())
||shareVisible.equals(SocFragment.class.toString())
||shareVisible.equals(DevFragment.class.toString())
){
MenuItem item=menu.findItem(R.id.action_share);
item.setVisible(false);
}
return super.onCreateOptionsMenu(menu);
}
in Kotlin
override fun onPrepareOptionsMenu(menu: Menu) {
val item: MenuItem = menu.findItem(R.id.action_search)
item.isVisible = false
}
in onCreate() of your fragment
setHasOptionsMenu(true)
There are many different versions of similar solutions but unfortunately, none of them worked for me. I am sharing what eventually was useful for me to hide the whole overflow menu with multiple menu items. Thought maybe it's useful for anyone.
I grouped my menus with an id and then referred that id
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.setGroupVisible(R.id.menu_overflow, false);
super.onPrepareOptionsMenu(menu);
}
If you want to hide any individual menu item then you can use
menu.getItem(R.id.action_licenses).setVisible(false);
Important thing is that you should have setOptionsMenu(true) in onViewCreated()
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
Call setHasOptionMenu(true) in onCreateView()
and Do not call super.onCreateOptionsMenu() in fragment's onCreateOptionMenu() instead call menu.clear() because this will override the existing menu with the activity's menu
This worked in my case.
Or solve it in the same Fragment which created the menu, if you host the Actionbar on Activity level. This way you don't have to add it on every other Fragment where you don't want to show it:
public override void OnDestroy()
{
base.OnDestroy();
HasOptionsMenu = false;
}
Add these functions to your Fragment
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem item=menu.findItem(R.id.delete);
item.setVisible(false);
}
Firstly in your Activity that has the toolbar, create a method that sets up the overflow menu for you:
public void setUpOptionMenu(Toolbar toolbar){
this.setSupportActionBar(toolbar);
}
In your fragments onCreateView() method, get the reference of your current activity and call your activities setUpOptionMenu() method:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
...
...
public void ((YourActivityName)this.getActivity()).setUpOptionMenu(null);
...
...
}
Cheers!!!
Overrride the following method just in your fragment and it will do the trick.
#Override
public void onCreateOptionsMenu(Menu menu,MenuInflater inflater) {
// Do something that differs the Activity's menu here
getActivity().getMenuInflater().inflate(R.menu.drawer, menu);
}
2022 KOTLIN
On your activity, where you navigate to fragments, You can try like below, On below code, Tested on Side Navigation view, It has been shown wherever needed using toolbar.inflateMenu(R.menu.toolbar_menu) and hidden using toolbar.menu.clear() on toolbar reference.
binding.naviSideNav.setNavigationItemSelectedListener(NavigationView.OnNavigationItemSelectedListener {
when (it.itemId) {
R.id.side_nav_home->{
toolbar.title=""
toolbar.menu.clear()
toolbar.inflateMenu(R.menu.toolbar_menu)
toolbar.setBackgroundColor(ContextCompat.getColor(this,R.color.home_screen_bg))
navController.navigate(R.id.navigation_home)
}
R.id.side_nav_appointments->{
}
R.id.side_nav_ehr->{
}
R.id.side_nav_invoices->{
}
R.id.side_nav_settings->{
toolbar.title=getString(R.string.nav_menu_Settings)
toolbar.menu.clear()
toolbar.setBackgroundColor(ContextCompat.getColor(this,R.color.home_screen_bg))
navController.navigate(R.id.navigation_settings)
}
R.id.side_nav_logout->{
}
}
binding.dlt.closeDrawer(GravityCompat.START)
true
})
Clean and redraw menu item
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
inflater.inflate(R.menu.main_menu, menu)
menu.findItem(R.id.id_menu_search)?.isVisible = true
super.onCreateOptionsMenu(menu, inflater)
}
I have checked the answers but now the optionMenu has been deprecated in the latest Android api level
setHasOptionsMenu(false)
so for the people who are using MenuProvider for optionMenu can use the
setMenuVisibility(false)
like this in fragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setMenuVisibility(false)
}
Just find the item you want to hide using findItem then set its visibility to false.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
MenuItem item = menu.findItem(R.id.action_settings);
item.setVisible(false);
}

onCreateOptionsMenu inside Fragments

I have placed setHasOptionsMenu(true) inside onCreateView, but I still can't call onCreateOptionsMenu inside fragments.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setHasOptionsMenu(true);
return inflater.inflate(R.layout.facesheet, container, false);
}
Below is my onCreateOptionsMenu code.
#Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
getSupportMenuInflater().inflate(R.menu.layout, menu);
return (super.onCreateOptionsMenu(menu));
}
The error message I get:
The method onCreateOptionsMenu(Menu) of type Fragment must override or implement a supertype method.
try this,
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_sample, menu);
super.onCreateOptionsMenu(menu,inflater);
}
Finally, in onCreateView method, add this line to make the options appear in your Toolbar
setHasOptionsMenu(true);
Your already have the autogenerated file res/menu/menu.xml defining action_settings.
In your MainActivity.java have the following methods:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_settings:
// do stuff, like showing settings fragment
return true;
}
return super.onOptionsItemSelected(item); // important line
}
In the onCreateView() method of your Fragment call:
setHasOptionsMenu(true);
and also add these 2 methods:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_1:
// do stuff
return true;
case R.id.action_2:
// do more stuff
return true;
}
return false;
}
Finally, add the new file res/menu/fragment_menu.xml defining action_1 and action_2.
This way when your app displays the Fragment, its menu will contain 3 entries:
action_1 from res/menu/fragment_menu.xml
action_2 from res/menu/fragment_menu.xml
action_settings from res/menu/menu.xml
I tried the #Alexander Farber and #Sino Raj answers. Both answers are nice, but I couldn't use the onCreateOptionsMenu inside my fragment, until I discover what was missing:
Add setSupportActionBar(toolbar) in my Activity, like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.id.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
I hope this answer can be helpful for someone with the same problem.
Call
setSupportActionBar(toolbar)
inside
onViewCreated(...)
of Fragment
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
((MainActivity)getActivity()).setSupportActionBar(toolbar);
setHasOptionsMenu(true);
}
Set setHasMenuOptions(true) works if application has a theme with Actionbar such as Theme.MaterialComponents.DayNight.DarkActionBar or Activity has it's own Toolbar, otherwise onCreateOptionsMenu in fragment does not get called.
If you want to use standalone Toolbar you either need to get activity and set your Toolbar as support action bar with
(requireActivity() as? MainActivity)?.setSupportActionBar(toolbar)
which lets your fragment onCreateOptionsMenu to be called.
Other alternative is, you can inflate your Toolbar's own menu with toolbar.inflateMenu(R.menu.YOUR_MENU) and item listener with
toolbar.setOnMenuItemClickListener {
// do something
true
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_add_customer, container, false);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_sample, menu);
super.onCreateOptionsMenu(menu,inflater);
}
You can do easily as,
inside your fragment on Create method,
setHasOptionsMenu(true)
and now you can override,
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
menu.clear()
}

Categories

Resources