How to add Options Menu to Fragment in Android

AndroidAndroid FragmentsAndroid Optionsmenu

Android Problem Overview


I am trying to add an item to the options menu from a group of fragments.

I have created a new MenuFragment class and extended this for the fragments I wish to include the menu item in. Here is the code:

Java:

public class MenuFragment extends Fragment {

    MenuItem fav;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

Kotlin:

class MenuFragment : Fragment {

    lateinit var fav: MenuItem

    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        fav = menu.add("add");
        fav.setIcon(R.drawable.btn_star_big_off);
    }
}

For some reason the onCreateOptionsMenu appears not to run.

Android Solutions


Solution 1 - Android

Call the super method:

Java:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		// TODO Add your menu entries here
		super.onCreateOptionsMenu(menu, inflater);
	}

Kotlin:

    override fun void onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

	override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
		// TODO Add your menu entries here
		super.onCreateOptionsMenu(menu, inflater)
	}

Put log statements in the code to see if the method is not being called or if the menu is not being amended by your code.

Also ensure you are calling setHasOptionsMenu(boolean) in onCreate(Bundle) to notify the fragment that it should participate in options menu handling.

Solution 2 - Android

I had the same problem, but I think it's better to summarize and introduce the last step to get it working:

  1. Add setHasOptionsMenu(true) method in your Fragment's onCreate(Bundle savedInstanceState) method.

  2. Override onCreateOptionsMenu(Menu menu, MenuInflater inflater) (if you want to do something different in your Fragment's menu) and onOptionsItemSelected(MenuItem item) methods in your Fragment.

  3. Inside your onOptionsItemSelected(MenuItem item) Activity's method, make sure you return false when the menu item action would be implemented in onOptionsItemSelected(MenuItem item) Fragment's method.

An example:

Activity

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getSupportMenuInflater();
    inflater.inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Do Activity menu item stuff here
            return true;

        case R.id.fragment_menu_item:

            // Not implemented here
            return false;
        default:
            break;
    }

    return false;
}

Fragment

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    ....
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // Do something that differs the Activity's menu here
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.activity_menu_item:

            // Not implemented here
            return false;
        case R.id.fragment_menu_item:

            // Do Fragment menu item stuff here
            return true;

        default:
            break;
    }

    return false;
}

Solution 3 - Android

If you find the onCreateOptionsMenu(Menu menu, MenuInflater inflater) method is not being invoked, make sure you call the following from the Fragment's onCreate(Bundle savedInstanceState) method:

setHasOptionsMenu(true)

Solution 4 - Android

If you need a menu to refresh a webview inside a specific Fragment, you can use:

Fragment:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    // TODO Add your menu entries here
    inflater.inflate(R.menu.menu, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.exit:
        System.exit(1);
        break;

    case R.id.refresh:
        webView.reload();
        break;
    }
    return true;

}

###menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/exit" android:title="Exit" android:icon="@drawable/ic_action_cancel" />
    <item android:id="@+id/refresh" android:title="Refresh" android:icon="@drawable/ic_action_refresh" />
</menu>

Solution 5 - Android

TL;DR

Use the android.support.v7.widget.Toolbar and just do:

toolbar.inflateMenu(R.menu.my_menu)
toolbar.setOnMenuItemClickListener {
    onOptionsItemSelected(it)
}

Standalone Toolbar

Most of the suggested solutions like setHasOptionsMenu(true) are only working when the parent Activity has the Toolbar in its layout and declares it via setSupportActionBar(). Then the Fragments can participate in the menu population of this exact ActionBar:

> Fragment.onCreateOptionsMenu(): Initialize the contents of the Fragment host's standard options menu.

If you want a standalone toolbar and menu for one specific Fragment you can to do the following:

menu_custom_fragment.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_save"
        android:title="SAVE" />
</menu>

custom_fragment.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    ...

CustomFragment.kt

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater.inflate(layout.custom_fragment, container, false)
    val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
    toolbar.inflateMenu(R.menu.menu_custom_fragment)
    toolbar.setOnMenuItemClickListener {
        onOptionsItemSelected(it)
    }
    return view
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.menu_save -> {
            // TODO: User clicked the save button
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Yes, it's that easy. You don't even need to override onCreate() or onCreateOptionsMenu().

PS: This is only working with android.support.v4.app.Fragment and android.support.v7.widget.Toolbar (also be sure to use AppCompatActivity and an AppCompat theme in your styles.xml).

Solution 6 - Android

In the menu.xml you should add all the menu items. Then you can hide items that you don't want to see in the initial loading.

menu.xml

<item
    android:id="@+id/action_newItem"
    android:icon="@drawable/action_newItem"
    android:showAsAction="never"
    android:visible="false"
    android:title="@string/action_newItem"/>

Add setHasOptionsMenu(true) in the onCreate() method to invoke the menu items in your Fragment class.

FragmentClass.java

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setHasOptionsMenu(true);
}

You don't need to override onCreateOptionsMenu in your Fragment class again. Menu items can be changed (Add/remove) by overriding onPrepareOptionsMenumethod available in Fragment.

@Override
public void onPrepareOptionsMenu(Menu menu) {
	menu.findItem(R.id.action_newItem).setVisible(true);
	super.onPrepareOptionsMenu(menu);

}

Solution 7 - Android

In my case, here is the steps.

Step-1

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Here notify the fragment that it should participate in options menu handling.
    setHasOptionsMenu(true);
}

Step-2

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // First clear current all the menu items
    menu.clear();

    // Add the new menu items
    inflater.inflate(R.menu.post_stuff, menu);

    super.onCreateOptionsMenu(menu, inflater);
}

Step-3

 @Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.post_stuff:
            Log.d(TAG, "Will post the photo to server");
            return true;
        case R.id.cancel_post:
            Log.d(TAG, "Will cancel post the photo");
            return true;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
}

Solution 8 - Android

You need to use menu.clear() before inflating menus.

@Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        menu.clear();
        inflater.inflate(R.menu.menu, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

and

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

Solution 9 - Android

If you want to add your menu custom

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_custom, menu);
}

Solution 10 - Android

I've had the same problem, my fragments were pages of a ViewPager. The reason it was happening is that I was using child fragment manager rather than the activity support fragment manager when instantiating FragmentPagerAdapter.

Solution 11 - Android

Menu file:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/play"
        android:titleCondensed="Speak"
        android:showAsAction="always"
        android:title="Speak"
        android:icon="@drawable/ic_play">
    </item>
    <item
        android:id="@+id/pause"
        android:titleCondensed="Stop"
        android:title="Stop"
        android:showAsAction="always"
        android:icon="@drawable/ic_pause">
    </item>
</menu>

Activity code:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.speak_menu_history, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.play:
            Toast.makeText(getApplicationContext(), "speaking....", Toast.LENGTH_LONG).show();
            return false;

        case R.id.pause:
            Toast.makeText(getApplicationContext(), "stopping....", Toast.LENGTH_LONG).show();
            return false;

        default:
            break;
    }

    return false;
}

Fragment code:

@Override

public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        case R.id.play:
            text = page.getText().toString();
            speakOut(text);

            // Do Activity menu item stuff here
            return true;

        case R.id.pause:
            speakOf();

            // Not implemented here
            return true;

        default:
            break;
    }
    return false;
}

Solution 12 - Android

Your code is fine. Only the super was missing in the method :

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // TODO add your menu : 
    inflater.inflate(R.menu.my_menu, menu);
    //TODO call super
    super.onCreateOptionsMenu(menu, inflater);
}

Solution 13 - Android

I was getting crazy because none of the answers here worked for me.

To show the menu I had to call: setSupportActionBar(toolbar)

Done!

Note: if your toolbar view isn't in the same activity layout you can't use the call above directly from your activity class, in this case you'll need to get that activity from your fragment class and then call the setSupportActionBar(toolbar). Remembering: your activity class should extends the AppCompatActivity.

Hope that this answer help you.

Solution 14 - Android

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
}

Solution 15 - Android

Setting the options menu after creating the fragment view worked well for me.

@Override
public void onActivityCreated(Bundle savedInstanceState) {
	super.onActivityCreated(savedInstanceState);
	setHasOptionsMenu(true);		
}

Solution 16 - Android

My problem was slightly different. I did everything right. But I was inheriting the wrong class for the activity hosting the fragment.

So to be clear, if you are overriding onCreateOptionsMenu(Menu menu, MenuInflater inflater) in the fragment, make sure your activity class which hosts this fragment inherits android.support.v7.app.ActionBarActivity (in case you would want to support below API level 11).

I was inheriting the android.support.v4.app.FragmentActivity to support API level below 11.

Solution 17 - Android

One thing I would add to this and the reason it was not working for me.

It is similar to Napster's answer.

  1. Make sure your fragment's hosting activity extends AppCompatActivity, not FragmentActivity!

    public class MainActivity extends AppCompatActivity {
    
    }
    

From the Google Reference Documentation for FragmentActivity:

> Note: If you want to implement an activity that includes an action bar, you should instead use the ActionBarActivity class, which is a subclass of this one, so allows you to use Fragment APIs on API level 7 and higher.

  1. To update Napster's answer -- ActionBarActivity now being deprecated, use AppCompatActivity instead.

  2. When using AppCompatActivity, also make sure you set "the activity theme toTheme.AppCompat or a similar theme" (Google Doc).

Note: android.support.v7.app.AppCompatActivity is a subclass of the android.support.v4.app.FragmentActivity class (see AppCompatActivity ref doc).

Solution 18 - Android

In your menu folder make a .menu xml file and add this xml

http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">

<item
    android:id="@+id/action_search"
    android:icon="@android:drawable/ic_menu_search"
    android:title="@string/action_search"
    app:actionViewClass="android.support.v7.widget.SearchView"
    app:showAsAction="always|collapseActionView" />

In your fragment class overide this method and

implement SearchView.OnQueryTextListener    in your fragment class



@Override
 public void onViewCreated(View view, Bundle savedInstanceState) {    
  super.onViewCreated(view, savedInstanceState);
  setHasOptionsMenu(true);
  
}

Now just setup your menu xml file in fragment class

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_main, menu);

    final MenuItem item = menu.findItem(R.id.action_search);
    final SearchView searchView = (SearchView)    
    MenuItemCompat.getActionView(item);


    MenuItemCompat.setOnActionExpandListener(item,
            new MenuItemCompat.OnActionExpandListener() {
                @Override
                public boolean onMenuItemActionCollapse(MenuItem item) {
                    // Do something when collapsed
                    
                    return true; // Return true to collapse action view
                }

                @Override
                public boolean onMenuItemActionExpand(MenuItem item) {
                    // Do something when expanded
                    return true; // Return true to expand action view
                }
            });

}

Solution 19 - Android

If all of the above does not work, you need to debug and make sure function onCreateOptionsMenu has been called (by placing debug or write log...)

If it's not run, maybe your Android theme is not supporting the action bar. Open AndroidManifest.xml and set the value for android:theme with theme support action bar:

 <activity
     android:name=".MainActivity"
     android:label="@string/app_name"
     android:theme="@style/Theme.AppCompat">

Solution 20 - Android

on your onCreate method add setHasOptionMenu()

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

Then override your onCreateOptionsMenu

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.add("Menu item")
            .setIcon(android.R.drawable.ic_delete)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}

Solution 21 - Android

This is what I did to hide and unhide ALL the menu options when the fragment is loaded and destroyed, respectively. It takes the risk out of pointing to null for R.id.your_menu_item and allowed me to reuse the fragment elsewhere.

lateinit var optionsMenu: Menu

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    menu.iterator().forEach {
        it.isVisible = false
    }
    optionsMenu = menu
    super.onCreateOptionsMenu(menu, inflater)
}

override fun onDestroyView() {
    optionsMenu.iterator().forEach {
        it.isVisible = true
    }
    super.onDestroyView()
}

Solution 22 - Android

In case none of the options above work for you, try this in your fragment:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 
....
        toolBar = rootView.findViewById(R.id.import_contacts_toolbar)
        toolBar?.title = "Your title"
        toolBar?.subtitle = "yor subtitile"
        contactsActivity().setSupportActionBar(toolBar)
        toolBar?.inflateMenu(R.menu.import_contacts_menu)
...
}



    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.1 -> {

                return true
            }
            R.id.2 -> {

                return true
            }
        }
    
        return false
    }





    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        menu.clear()
        inflater.inflate(R.menu.import_contacts_menu, menu)
        super.onCreateOptionsMenu(menu, inflater)

        val search = menu.findItem(R.id.action_search)
        val searchView = search.actionView as SearchView
        searchView.requestFocus()

        val txtSearch = searchView.findViewById<View>(androidx.appcompat.R.id.search_src_text) as EditText
        txtSearch.hint = "Search..."
        txtSearch.setHintTextColor(Color.WHITE);
        txtSearch.setTextColor(Color.WHITE)

        try {
            val f: Field = TextView::class.java.getDeclaredField("mCursorDrawableRes")
            f.setAccessible(true)
            f.set(txtSearch, R.drawable.search_edit_text_cursor)
        } catch (ignored: Exception) {
            Log.d(TAG, "failed to expose cursor drawable $ignored")
        }

        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                return false
            }

            override fun onQueryTextChange(newText: String): Boolean {

                return true
            }
        })
        searchView.setOnCloseListener {
            
        }
    }

In my case I had a search menu item which was set to always visible. This is the xml for it:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_search"
        app:showAsAction="always"
        app:actionViewClass="androidx.appcompat.widget.SearchView"
        android:title="Search"/>

    <item android:id="@+id/1"
        android:title="1">
    </item>

    <item android:id="@+id/2"
        android:title="2">
    </item>
</menu>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmisterbassmanView Question on Stackoverflow
Solution 1 - AndroidKuffsView Answer on Stackoverflow
Solution 2 - AndroidMarco HernaizView Answer on Stackoverflow
Solution 3 - AndroidMatthew BlackfordView Answer on Stackoverflow
Solution 4 - AndroidPedro LobitoView Answer on Stackoverflow
Solution 5 - AndroidmboView Answer on Stackoverflow
Solution 6 - AndroidParinda RajapakshaView Answer on Stackoverflow
Solution 7 - AndroidHarry ZhangView Answer on Stackoverflow
Solution 8 - AndroidSpl2nkyView Answer on Stackoverflow
Solution 9 - AndroidEzequiel GarcíaView Answer on Stackoverflow
Solution 10 - Androidfarid_zView Answer on Stackoverflow
Solution 11 - AndroidSuyog GunjalView Answer on Stackoverflow
Solution 12 - AndroidAlexPadView Answer on Stackoverflow
Solution 13 - AndroidFilipe BritoView Answer on Stackoverflow
Solution 14 - AndroidThracianView Answer on Stackoverflow
Solution 15 - AndroidJerry FrostView Answer on Stackoverflow
Solution 16 - AndroidKrishna DeepakView Answer on Stackoverflow
Solution 17 - AndroidbastienView Answer on Stackoverflow
Solution 18 - AndroidpavelView Answer on Stackoverflow
Solution 19 - AndroidGrey WolfView Answer on Stackoverflow
Solution 20 - AndroidAshana.JackolView Answer on Stackoverflow
Solution 21 - AndroidMichaelView Answer on Stackoverflow
Solution 22 - Androidandroid enthusiastView Answer on Stackoverflow