Simple question.
I have my menu of child items:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/fp_pitcher"
android:title="Pitcher">
</item>
<item
android:id="@+id/fp_catcher"
android:title="Catcher">
</item>
<!-- SNIP --->
</menu>
And later I would want to include it as a submenu of this menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/teameditor_remove"
android:title="Remove Player from Team">
</item>
<item
android:id="@+id/teameditor_assignbattingposition"
android:title="Assign Batting Position">
</item>
<item
android:id="@+id/teameditor_assignfieldingposition"
android:title="Assign Feilding Position">
<!-- I want to include the submenu here-->
</item>
</menu>
The question here kind of answered this - I'm not sure how to inflate the submenu.
I'm thinking that you inflate it in the onContextItemSelected method - but inflate requires a menu object, which isn't passed into onContextItemSelected.
It's sadly not possible in plain XML, but there's a nice way without using manual Menu.add*
methods: here's how you can obtain a Menu
instance to include/inflate the other file into:
inflater.inflate(R.menu.player, menu);
MenuItem fp_menu = menu.findItem(R.id.teameditor_assignfieldingposition);
inflater.inflate(R.menu.positions, fp_menu.getSubMenu()); // needs <menu />
You can put the above code to any of the following using the specified inflater
:
Activity.onCreateContextMenu(menu, v, menuInfo)
: getMenuInflater()
Fragment.onCreateContextMenu(menu, v, menuInfo)
: getActivity().getMenuInflater()
Activity.onCreateOptionsMenu(menu)
: getMenuInflater()
Fragment.onCreateOptionsMenu(menu, inflater)
: inflater
menu/player.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/teameditor_remove"
android:title="Remove Player from Team"
/>
<item android:id="@+id/teameditor_assignbattingposition"
android:title="Assign Batting Position"
/>
<item android:id="@+id/teameditor_assignfieldingposition"
android:title="Assign Feilding Position">
<menu><!-- include: positions.xml --></menu>
</item>
</menu>
The empty <menu />
placeholder is very important, without that getSubMenu()
will be null
!
menu/positions.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/fp_pitcher"
android:title="Pitcher"
/>
<item android:id="@+id/fp_catcher"
android:title="Catcher"
/>
<!-- SNIP --->
</menu>
Note on your onContextItemSelected
idea
I'm thinking that you inflate it in the onContextItemSelected
method [...]
I think it's too late if you're in onContextItemSelected
, since you're already handling the event which would lead to showing you're submenu... which is not inflated yet. You could try the same inflate into getSubMenu()
, but I'm not sure that it'll show up. It's best to create the menu where it's supposed to be created.
Note on including the same submenu multiple times in the same menu
Untested If you need to inflate the same positions.xml
into teameditor_assignbattingposition
as well you'll have some problems in onOptionsItemSelected
/onContextItemSelected
.
One way to work around it is to convert the findItem
variable to a field and save the reference to both
this.fp_menu = menu.findItem(R.id.teameditor_assignfieldingposition);
inflater.inflate(R.menu.positions, fp_menu.getSubMenu());
this.bp_menu = menu.findItem(R.id.teameditor_assignbattingposition);
inflater.inflate(R.menu.positions, bp_menu.getSubMenu());
and then in on*ItemSelected
:
switch (item.getItemId()) {
case R.id.fp_pitcher:
if (item == fp_menu.findItem(R.id.fp_pitcher)) {
// selected inside teameditor_assignfieldingposition
} else if (item == bp_menu.findItem(R.id.fp_picther)) {
// selected inside teameditor_assignbattingposition
} else {
throw new ImLostInMenusException();
}
return true;
}
return super.on*ItemSelected();
It's not pretty, but if you you need to do it without copying the XML content over (which would work easily). When you inflate the second menu you can also do a menu.findItem(R.id.teameditor_assignfieldingposition).getSubMenu().add(...)
for each of the items you want to add. If you have the strings ("Pitcher" and "Catcher") in a String array resource you could iterate over that array to add the same items as in the original. Alternatively, you would probably need to parse the other menu's XML, you can cheat that by just inflating it I guess, and then using it's size()
and getItem(int)
.
In fact, you could just inflate the first menu into a Menu
and then use size()
and getItem(int)
to get the MenuItem
s out of it. Then, for each item you can do add(menuItem.getGroupId(), menuItem.getItemId(), menuItem.getOrder(), menuItem.getTitle())
on the getSubMenu()
of the second menu's findItem(R.id.teameditor_assignfieldingposition)
. That should add all the items of the first menu as a submenu of that item. This means you are inflating two XML files, but it's kind of unavoidable if you want to use separate XML files, seeing as there isn't an <include>
for menu XML files. I would probably inflate the second menu normally (in the onCreateOptionsMenu(...)
) and then add the first menu as a submenu in the onPrepareOptionsMenu(...)
(it's given the menu you created in onCreateOptionsMenu(...)
). I think you could do it all in onCreateOptionsMenu(...)
, but I believe it's better practice to make modifications to the menu in onPrepareOptionsMenu(...)
.
I think the second way is the best solution I can find, I'm leaving the first option as an alternative just in case.