Android: 如何在一个菜单xml文件中包含另一个菜单xml文件?

6

简单问题。

我有一个子项目的菜单:

<?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 方法中扩展它 - 但是 inflate 需要一个菜单对象,而该对象并未传递到 onContextItemSelected 方法中。

2个回答

3
很遗憾,普通的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

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>

空的<menu />占位符非常重要,没有它,getSubMenu()会是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>

关于你的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();

0

虽然不太美观,但如果您需要在不复制XML内容的情况下完成它(这很容易),那么可以使用以下方法:当您填充第二个菜单时,您还可以为要添加的每个项目执行menu.findItem(R.id.teameditor_assignfieldingposition).getSubMenu().add(...)。 如果您在String数组资源中有字符串(“Pitcher”和“Catcher”),则可以迭代该数组以添加与原始项目相同的项目。 或者,您可能需要解析其他菜单的XML,我猜您可以通过简单地充气来欺骗它,然后使用其size()getItem(int)

实际上,您可以将第一个菜单膨胀为一个Menu,然后使用size()getItem(int)从中获取MenuItem。然后,对于每个项目,您可以在第二个菜单的findItem(R.id.teameditor_assignfieldingposition)getSubMenu()上执行add(menuItem.getGroupId(), menuItem.getItemId(), menuItem.getOrder(), menuItem.getTitle())。这应该将第一个菜单的所有项目添加为该项的子菜单。这意味着您正在膨胀两个XML文件,但如果您想使用单独的XML文件,这是不可避免的,因为菜单XML文件没有<include>。我可能会在onCreateOptionsMenu(...)中正常膨胀第二个菜单,然后在onPrepareOptionsMenu(...)中将第一个菜单作为子菜单添加到其中(它会得到您在onCreateOptionsMenu(...)中创建的菜单)。我认为您可以在onCreateOptionsMenu(...)中完成所有操作,但我认为在onPrepareOptionsMenu(...)中修改菜单是更好的做法。

我认为第二种方式是我能找到的最佳解决方案,我将第一选择作为备选方案。


如果您使用 getSubMenu() 直接将其inflate到其中,就不需要手动复制使用 add。此外,获取“*一个[临时]Menu[...]以从中获取MenuItem*”是有点不可能的。 - TWiStErRob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接