38

我想在方法 onCreateOptionsMenu扩展一个菜单对象(这意味着在用户不按下按钮时创建/显示菜单),所以我需要创建一个菜单实例以将其传递给 inflate 方法。

这是我要实现的目标的示例:

Menu menu = // How to create an instance !? 
new MenuInflater(context).inflate(R.menu.my_menu, menu)

Menu 是一个接口,所以我需要知道哪个类正在实现它。我确实浏览了 Android 代码以获取有关如何创建 Menu 对象的任何提示,但仍然找不到我要查找的内容。

编辑 1

我的目标是从自定义视图中触发一个onOptionsItemSelected(MenuItem item)事件,该事件将由活动处理,因此我需要一个具有特定 itemId 和标题的 MenuItem 对象以将其与事件一起传递。

如果我能成功地创建一个 Menu 对象,就很容易得到它的子 MenuItems。

编辑 2

根本不想显示菜单,我想要的是使用菜单 XML 中定义的元素填充 ListView ,这些元素具有标题、图标和itemId,并且每当单击 ListViewItem 时,我都想触发在我的活动。onOptionsItemSelected(MenuItem item)

onOptionsItemSelected(MenuItem item)我知道我可以解析菜单 XML 以提取项目信息,但是如果不创建标准MenuItem 对象将其作为参数传递,我将无法触发。

任何帮助将不胜感激。谢谢!

4

5 回答 5

48

这是获取 Menu 实例的技巧:

PopupMenu p  = new PopupMenu(getContext(), null);
Menu menu = p.getMenu();
于 2014-07-14T04:10:21.997 回答
29

我找到了两种以编程方式创建 Menu 实例并对其进行膨胀的解决方案:

// 通过反射创建实例

Menu menu = newMenuInstance(context);


protected Menu newMenuInstance(Context context) {
    try {
        Class<?> menuBuilderClass = Class.forName("com.android.internal.view.menu.MenuBuilder");

        Constructor<?> constructor = menuBuilderClass.getDeclaredConstructor(Context.class);

        return (Menu) constructor.newInstance(context);

    } catch (Exception e) {e.printStackTrace();}

    return null;
}

一旦你有了一个 Menu 实例,你就可以很容易地从你程序中任何地方的菜单 XML 资源扩展它

new MenuInflater(context).inflate(menuId, menu);

我测试了这两种方法并且它们运行良好,我建议将第二种方法与android SDK中的标准Menu和类一起使用,即使您的活动扩展了 SherlockActivity,因为无论您使用或触发它,它仍然会接收MenuItemonOptionsItemSelected(MenuItem item)android.view.MenuItemcom.actionbarsherlock.view.MenuItem

于 2013-01-04T04:36:55.277 回答
6

我不确定为什么这不是一个答案,而且我知道这是一个老问题,但对于未来的读者..

如果你只是这样做:

val menu = MenuBuilder(context)
MenuInflater(context).inflate(R.menu.menu_XXXX, menu)

有用!

androidx.appcompat.view.menu.MenuBuilder实现android.view.Menu。经检查,仅此PopupMenu而已。

请注意,com.android.internal.view.menu.MenuBuilder@iTech 提到并使用的PopupMenu不是公开的,不应使用。

下面是两个辅助函数和一个使用示例:

fun Context.inflateMenu(@MenuRes menuRes: Int): Lazy<MenuBuilder> = lazy {
    MenuBuilder(this)
        .also { MenuInflater(this).inflate(menuRes, it) }
}

fun Fragment.inflateMenu(@MenuRes menuRes: Int): Lazy<MenuBuilder> = lazy {
    MenuBuilder(context)
        .also { MenuInflater(context).inflate(menuRes, it) }
}

用法:

活动

class MyActivity : AppCompatActivity(R.layout.activity_my) {

    val menu by inflateMenu(R.menu.menu_my)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ...
    }
}

分段:

class MyFragment : Fragment(R.layout.fragment_my) {

    val menu by inflateMenu(R.menu.menu_my)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        ...
    }
}
于 2019-09-26T21:51:29.833 回答
2

你不需要对充气机做任何事情来添加你自己的菜单。只需覆盖并开始在菜单对象中onCreateOptionsMenu添加您自己的项目。例如:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    menu.add(0, 1, Menu.NONE, "First");
    menu.add(0, 2, Menu.NONE, "Second");
    // repeat this to add additional menus

    return true;
}

add方法中的第二个参数是id. 使用唯一ID来标识您选择的菜单项。

于 2013-01-02T08:29:14.300 回答
0

您可以拉取存储在 Activity 中使用的 PhoneWindow 中的 MenuBuilder 实例(实现 Menu 接口)。我有一个可行的解决方案,它使用 Java 反射。

我创建了一个项目“InDroid”来公开几个重要的隐藏方法,来自 Android 平台的变量 - http://code.google.com/p/indroid/

BR,普拉桑塔

于 2013-04-07T09:00:58.553 回答