457

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.

ChrisMcJava
  • 2,145
  • 5
  • 25
  • 33
misterbassman
  • 4,589
  • 2
  • 14
  • 4
  • maybe a silly question... you press the menu button right? – Ovidiu Latcu Nov 29 '11 at 09:56
  • 2
    ..lol...yes I have pressed the menu button, I have also tried it with and without: fav.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); – misterbassman Nov 29 '11 at 10:19
  • Hi, maybe [this](http://stackoverflow.com/a/6324275/703919) thread will help you or check the [api demo](http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentMenu.html) for a working example. – kameny Nov 29 '11 at 10:47
  • https://droidmentor.com/how-to-use-fragment-specific-menu-in-android/ – the_prole Jun 21 '19 at 17:51
  • There is a new of doing this since androidx.activity:activity:1.4.0. See my new answer: https://stackoverflow.com/a/73080607/8133841 – Gesit Jul 22 '22 at 12:50

25 Answers25

680

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.

Kuffs
  • 35,581
  • 10
  • 79
  • 92
  • 2
    Thanks for the help, I added the super method, and realised I had removed the @Override so added this back in, eclipse threw an error so I replaced the MenuInflater to import android.view.MenuInflater; instead of import android.support.v4.view.MenuInflater; and now all is working – misterbassman Nov 29 '11 at 10:53
  • 196
    not calling setHasOptionsMenu(true) in the Fragment's onCreate has gotten me twice now – joshkendrick Jun 13 '12 at 12:54
  • 7
    I was transferring my Activity to a Fragment and ran into this issue. The method signature has changed from public boolean to public void and the arguments have also changed. Make sure to take note of this! – you786 Jun 19 '12 at 03:24
  • 15
    Note that Fragment.onCreateOptionsMenu(Menu, MenuInflater) is an empty method, so calling super is not required at all. The only mistake here was the wrong method signature and possibly a missing setHasOptionsMenu() in onCreate() – cmende Jul 17 '13 at 10:14
  • That may be so but it is still worth mentioning for the people using Activities instead of Fragments and by the upvotes, many people agree and were helped by this answer. – Kuffs Jul 22 '13 at 07:32
  • 1
    You know, in Java a method is identified, in part, with a name (as you used), and a CLASS. So, please, when you suggest to override a method, please, please give the class. Especially as there are two objects that may be manipulated (`Fragment`and `Activity`, and the `Fragment` usually has its `onCreateView()` method overridden while the `Activity` has its `onCreate()` method overridden). – Vince Nov 21 '14 at 05:56
  • 1
    The question already stated that the Class was Fragment as part of its text and in the code sample. There was no need to repeat it. – Kuffs Nov 21 '14 at 06:24
  • is it possible to first remove all existing items from the menu then add an item. – sarfarazsajjad Feb 15 '16 at 12:28
  • @Saifee please open your own question as what you asked is not relevant to this one. – Kuffs Feb 15 '16 at 12:37
  • I'm using a `Toolbar` and had to call `setHasOptionsMenu(true)` in `onCreateView()` instead `onCreate()` to get it done. – CLOUGH Aug 19 '16 at 11:27
  • 6
    Replace super.onCreateOptionsMenu with inflater.inflate(R.menu.menu_custom, menu); – Code_Worm Oct 18 '16 at 14:39
  • There is a new of doing this since `androidx.activity:activity:1.4.0`. See my new answer: https://stackoverflow.com/a/73080607/8133841 – Gesit Jul 22 '22 at 12:50
  • onCreateOptionMenu is deprected. how can we acheive this with addMenuProvider ? – Raghu Krishnan R Feb 16 '23 at 06:36
218

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;
}
Marcel50506
  • 1,280
  • 1
  • 14
  • 32
Marco Hernaiz
  • 5,830
  • 3
  • 27
  • 27
162

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)
Matthew Blackford
  • 3,041
  • 1
  • 24
  • 28
  • It gives me Error like NullPointerException – Pratik Butani Jun 20 '13 at 13:01
  • 2
    Good point. I was calling the setHasOptionMenu method from the static newInstance method. As I was only attaching my fragment when savedInstanceState was null, when the screen configuration changed the menu would not be created. The onCreate method of the fragment is the correct place where to set setHasOptionMenu to true. – argenkiwi Aug 17 '13 at 03:56
  • 1
    I'm using a `Toolbar` and had to call `setHasOptionsMenu(true)` in `onCreateView()` instead `onCreate()` to get it done. – CLOUGH Aug 19 '16 at 11:28
  • **'setHasOptionsMenu(Boolean): Unit' is deprecated. Deprecated in Java.** This method is no longer needed when using a MenuProvider to provide a Menu to your activity, which replaces onCreateOptionsMenu as the recommended way to provide a consistent, optionally Lifecycle-aware, and modular way to handle menu creation and item selection. – philoopher97 Jan 22 '23 at 06:22
82

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>
Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
  • 1
    This is a great answer, where I was looking for a way to merge app bar from activity and additional options coming from fragment, thanks! – Teoman shipahi Jul 11 '20 at 05:34
49

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).

mbo
  • 4,611
  • 2
  • 34
  • 54
27

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);

}
akash bs
  • 258
  • 6
  • 15
Parinda Rajapaksha
  • 2,963
  • 1
  • 36
  • 40
21

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);
}
Harry Zhang
  • 799
  • 9
  • 6
17

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);
    }
Spl2nky
  • 614
  • 5
  • 10
17

There is a new way of doing this since androidx.activity:activity:1.4.0

You are supposed to use the MenuProvider API.

It is used as follows:

Instead of calling super.setHasOptionMenu and implementing onCreateOptionsMenu you are supposed to call addMenuProvider in onViewCreated.

An Example:

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 true
      }
    }, viewLifecycleOwner)
  }

source: Activity Changelog

Gesit
  • 329
  • 2
  • 13
  • latest and modern way to add menu with fragment.. – Dhananjay pathak Aug 01 '22 at 07:32
  • @Gesit val menuHost: MenuHost = requireActivity() ? can you elaborate this ? MenuHost given type, but you set FragmentActivity instead – Gideon Steven Oct 31 '22 at 23:46
  • @GideonSteven MenuHost is just an interface which is implemented by FragmentActivity. It would also be possible to make menuHost FragmentActivity and call these methods directly. – Gesit Nov 18 '22 at 21:33
8

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);
}
Gowthaman M
  • 8,057
  • 8
  • 35
  • 54
Ezequiel García
  • 2,616
  • 19
  • 12
7

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.

P1nGu1n
  • 594
  • 8
  • 23
farid_z
  • 1,673
  • 21
  • 11
3

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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Suyog Gunjal
  • 287
  • 4
  • 7
3

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);
}
Ajil O.
  • 6,562
  • 5
  • 40
  • 72
AlexPad
  • 10,364
  • 3
  • 38
  • 48
2

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.

Filipe Brito
  • 5,329
  • 5
  • 32
  • 42
2

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
}
Thracian
  • 43,021
  • 16
  • 133
  • 222
2

Now on 2022, Google deprecated setHasOptionsMenu and you should use MenuProvider instead. In my experience, I got NoSuchMethodException on some android 11, 12 when I used setHasOptionsMenu method.

This method is no longer needed when using a MenuProvider to provide a Menu to your activity, which replaces onCreateOptionsMenu as the recommended way to provide a consistent, optionally Lifecycle-aware, and modular way to handle menu creation and item selection.

This is how you add menu to your activity/fragment atm:

/**
  * Using the addMenuProvider() API directly in your Activity
  **/
class ExampleActivity : ComponentActivity() {

  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() {

  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 true
      }
    }, viewLifecycleOwner, Lifecycle.State.RESUMED)
  }

Here's reference link.

Ah, for lazy one as me, you must add this as well:

dependencies {
    val activity_version = "1.5.1"

    // Java language implementation
    implementation("androidx.activity:activity:$activity_version")
    // Kotlin
    implementation("androidx.activity:activity-ktx:$activity_version")
}

Kingfisher Phuoc
  • 8,052
  • 9
  • 46
  • 86
1

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

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setHasOptionsMenu(true);        
}
Jerry Frost
  • 467
  • 4
  • 6
1

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Krishna Deepak
  • 1,735
  • 2
  • 20
  • 31
1

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.

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

  3. 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).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bastien
  • 2,940
  • 1
  • 13
  • 23
1

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

<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
                }
            });

}
pavel
  • 1,603
  • 22
  • 19
0

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">
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Wolf
  • 6,361
  • 2
  • 28
  • 25
0

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);
}
Ashana.Jackol
  • 3,064
  • 28
  • 22
0

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()
}
Michael
  • 748
  • 8
  • 11
0

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>
android enthusiast
  • 2,062
  • 2
  • 24
  • 45
0

Here's how to do it with a custom toolbar in a fragment. It is similar to the method by mbo but with the deprecated method replaced.

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    this.rootView = inflater.inflate(R.layout.fragment_study_list, container, false) as DrawerLayout



    // Set the menu
    val toolbar = this.rootView.findViewById<Toolbar>(R.id.studylist_toolbar)

    toolbar.addMenuProvider(object : MenuProvider {

        override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
            // Add menu items here
            menuInflater.inflate(R.menu.studylist_menu, menu)
        }

        override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
            // Handle the menu selection

            Log.d("CONJUU","Menu clicked")

            return true
        }
    }, viewLifecycleOwner, Lifecycle.State.RESUMED)
}
Joseph Williamson
  • 771
  • 1
  • 6
  • 18