Android: как включить меню xml в другое меню 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>
    <item
        android:id="@+id/fp_catcher"
        android:title="Catcher">
    </item>
<!-- SNIP ---> 
</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>

Вопрос здесь как бы ответил на это - я не уверен, как раздуть подменю .

Я думаю, что вы раздуваете его в методе onContextItemSelected, но для раздувания требуется объект меню, который не передается в onContextItemSelected.


person dwjohnston    schedule 11.07.2012    source источник


Ответы (2)


К сожалению, это невозможно в простом XML, но есть хороший способ без использования ручных методов Menu.add*: вот как вы можете получить экземпляр Menu для включения/раздувания другого файла в:

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 />

Вы можете поместить приведенный выше код в любое из следующего, используя указанный inflater:

  • Activity.onCreateContextMenu(menu, v, menuInfo): getMenuInflater()
  • Fragment.onCreateContextMenu(menu, v, menuInfo): getActivity().getMenuInflater()
  • Activity.onCreateOptionsMenu(menu): getMenuInflater()
  • Fragment.onCreateOptionsMenu(menu, inflater): inflater

меню/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>

Пустой заполнитель <menu /> очень важен, без него getSubMenu() будет null!

меню/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>

Обратите внимание на вашу onContextItemSelected идею

Я думаю, что вы надуваете его в методе onContextItemSelected [...]

Я думаю, что слишком поздно, если вы находитесь в onContextItemSelected, поскольку вы уже обрабатываете событие, которое приведет к отображению вашего подменю... которое еще не раздуто. Вы можете попробовать то же самое надуть в getSubMenu(), но я не уверен, что это появится. Лучше всего создать меню там, где оно должно быть создано.

Примечание о включении одного и того же подменю несколько раз в одно и то же меню.

Не проверено Если вам нужно преобразовать те же positions.xml в teameditor_assignbattingposition, у вас возникнут проблемы с onOptionsItemSelected/onContextItemSelected. Один из способов обойти это — преобразовать переменную findItem в поле и сохранить ссылку на оба

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

а затем в 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();
person TWiStErRob    schedule 09.12.2014

Это некрасиво, но если вам нужно сделать это без копирования содержимого XML (что будет легко работать). Когда вы расширяете второе меню, вы также можете сделать menu.findItem(R.id.teameditor_assignfieldingposition).getSubMenu().add(...) для каждого элемента, который хотите добавить. Если у вас есть строки ("Pitcher" и "Catcher") в ресурсе массива String, вы можете выполнить итерацию по этому массиву, чтобы добавить те же элементы, что и в оригинале. В качестве альтернативы вам, вероятно, потребуется проанализировать XML другого меню, вы можете обмануть это, просто раздув его, я думаю, а затем используя его size() и getItem(int).

На самом деле, вы можете просто раздуть первое меню до Menu, а затем использовать size() и getItem(int), чтобы получить из него MenuItem. Затем для каждого элемента вы можете сделать add(menuItem.getGroupId(), menuItem.getItemId(), menuItem.getOrder(), menuItem.getTitle()) в getSubMenu() второго меню findItem(R.id.teameditor_assignfieldingposition). Это должно добавить все элементы первого меню в качестве подменю этого элемента. Это означает, что вы создаете два XML-файла, но это неизбежно, если вы хотите использовать отдельные XML-файлы, поскольку для XML-файлов меню нет <include>. Я бы, наверное, раздул второе меню нормально (в onCreateOptionsMenu(...)), а затем добавил первое меню в качестве подменю в onPrepareOptionsMenu(...) (это меню, которое вы создали в onCreateOptionsMenu(...)). Я думаю, вы могли бы сделать все это в onCreateOptionsMenu(...), но я считаю, что лучше вносить изменения в меню в onPrepareOptionsMenu(...).

Я думаю, что второй способ - лучшее решение, которое я могу найти, я оставляю первый вариант в качестве альтернативы на всякий случай.

person Dandre Allison    schedule 29.11.2012
comment
Если вы используете getSubMenu() просто inflate в него напрямую, нет необходимости копировать вручную с помощью add. Кроме того, получить [временный] Menu [...], чтобы получить от него MenuItems, практически невозможно. - person TWiStErRob; 10.12.2014