How to add submenu items to ActionBar action in code?

70,643

Solution 1

Yes, there is.

The addSubMenu method returns a SubMenu object. A SubMenu is also a Menu, so you can call add on it to add items to the submenu rather than the parent menu. Your code above is creating two different submenus for Form 1 and Form 2 rather than two items within a single New Form submenu.

Example:

SubMenu submenu = menu.addSubMenu(0, Menu.NONE, 1, "New Form").setIcon(R.drawable.ic_new_form);
submenu.add("Form 1").setIcon(R.drawable.attachment);

Solution 2

Adding an ActionProvider maybe it's easier. You can try as explained here

Solution 3

You should consider to use an ActionProvider

example: https://gist.github.com/sibelius/7ca0b757492ff6740dec

Menu with action provider item

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

    <item android:id="@+id/action_companies"
        android:icon="@drawable/ic_list"
        android:title="@string/action_companies"
        app:actionProviderClass="com.example.MyActionProvider"
        app:showAsAction="always"/>
</menu>

Code

public class MyActionProvider extends ActionProvider {

    private Context mContext;

    public MyActionProvider(Context context) {
        super(context);

        mContext = context;
    }

    @Override
    public View onCreateActionView() {
        //LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        return null;
    }

    @Override
    public void onPrepareSubMenu(SubMenu subMenu) {
        super.onPrepareSubMenu(subMenu);

        subMenu.clear();

        subMenu.add("menu 1");
        subMenu.add("menu 2");
        subMenu.add("menu 3");
    }

    @Override
    public boolean hasSubMenu() {
        return true;
    }

    @Override
    public boolean onPerformDefaultAction() {
        return super.onPerformDefaultAction();
    }
}
Share:
70,643
Mathias Conradt
Author by

Mathias Conradt

Cybersecurity Professional (CIAM, AppSec, DevSecOps, OSINT), Software Engineer, Open Source Enthusiast, Privacy Advocate, Tactical &amp; Stealth Gamer, Motor Biker.

Updated on July 08, 2022

Comments

  • Mathias Conradt
    Mathias Conradt almost 2 years

    Via xml I can add submenu items to my action in the ActionBar.

    enter image description here

    main_menu.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/menu_new_form"
              android:icon="@drawable/ic_new_form"
              android:title="@string/menu_new_form"
              android:showAsAction="ifRoom|withText">
            <menu>
                <item android:id="@+id/form1"
                      android:icon="@drawable/attachment"
                      android:title="Form 1"
                      android:onClick="onSort" />
                <item android:id="@+id/form2"
                      android:icon="@drawable/attachment"
                      android:title="Form 2"
                      android:onClick="onSort" />
            </menu>
        </item>
    </menu>
    

    But how can I add these sub items via Java code? It doesn't work as below, the sub items are getting added to the wrong action (and also the drawable isn't shown), the very right button, not my 'New Form' button:

    enter image description here

    main_menu.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/menu_new_form"
              android:icon="@drawable/ic_new_form"
              android:title="@string/menu_new_form"
              android:showAsAction="ifRoom|withText">
        </item>
    </menu>
    

    Java Code:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
    
        Log.d("MainMenu", ",menu title0: " + menu.getItem(0).getTitle()); 
        // returns "New Form"
    
        menu.addSubMenu(0, Menu.NONE, 1, "Form 1").setIcon(R.drawable.attachment);
        menu.addSubMenu(0, Menu.NONE, 2, "Form 2").setIcon(R.drawable.attachment);
        return true;
    }
    

    Is there a way to achieve this, adding sub menu items via Java Code instead of XML, without using a PopupMenu (http://developer.android.com/guide/topics/ui/menus.html#PopupMenu)?

    Update (Solution):

    My final code snippet I ended up with to populate the submenu dynamically, following adamp's reply:

    // menu options
    private static final int MENU_PREFERENCES = Menu.FIRST;
    private static final int MENU_LOGOUT = 2;
    
    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        super.onCreateOptionsMenu(menu);
    
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        menu.add(0, MENU_PREFERENCES, 0, getString(R.string.general_preferences)).setIcon(
                android.R.drawable.ic_menu_preferences);
    
        // load all available form templates
        Cursor c = managedQuery(FormsProviderAPI.FormsColumns.CONTENT_URI, null, null, null, null);
        try {
            int ixDisplayName = c.getColumnIndex(FormsProviderAPI.FormsColumns.DISPLAY_NAME);
            int ixId = c.getColumnIndex(FormsProviderAPI.FormsColumns._ID);
            int cnt = 0;
            while (c.moveToNext()) {
                cnt++;
                Log.d("ID: ", "ID: "+ c.getInt(ixId));  // misusing the group id for the form id
                menu.getItem(1).getSubMenu().addSubMenu(c.getInt(ixId), Menu.NONE, cnt, c.getString(ixDisplayName)).setIcon(R.drawable.attachment_dark);
            }
        } catch (Exception e) {
            Log.e(TAG, "Error init form templates list.", e);
        }
    
        return true;
    }
    
  • Mathias Conradt
    Mathias Conradt about 12 years
    Thanks, I had already figured it out yesterday and working now. I thought I could use the groupIds for that, thought that was their purpose of it and they hang the item into the correct hierarchy. Thanks again.
  • adamp
    adamp about 12 years
    The group IDs are used for other forms of logical grouping. For example, if menu items appear in the action bar as "ifRoom", items in the same group will overflow together - either all of the items in the group will appear in the bar or all of the items will move to the overflow menu. It's useful for related commands that should not be separated in presentation.
  • Chirag Patel
    Chirag Patel about 12 years
    @MathiasLin How did you solved this problem ? Because I am facing the same. But as adamp suggested It adds submenu in main menu(New Form in main menu) and then we click on "New form", it shows "Form 1" item but even though drawable does not appeared. Can you share some code please ?
  • Mathias Conradt
    Mathias Conradt about 12 years
    @chiragsaga I followed adamp's hint and it works fine for me. I will update/add the code in my original question.
  • C--
    C-- over 10 years
    And if someone is looking for adding items to the submenu's which already does exist from the XML, use menu.getItem(<index>).getSubMenu().add("menu item");