如何以编程方式创建Menu实例?即在onCreateOptionsMenu外面扩展菜单

时间:2013-01-02 08:18:36

标签: android android-layout menu menuitem

我想在菜单对象外面 onCreateOptionsMenu方法中膨胀(这意味着当用户没有按下按钮时创建/显示菜单),所以我需要创建一个菜单实例将其传递给inflate方法。

这是我想要实现的一个例子:

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

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

修改1

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

如果我可以成功创建一个Menu对象,那么很容易获得它的子MenuItems。

修改2

尝试显示菜单,我想要的是使用菜单XML中定义的元素填充ListView 具有title,icon和itemId,每当单击ListViewItem时,我想触发在我的活动中处理的onOptionsItemSelected(MenuItem item)事件

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

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

5 个答案:

答案 0 :(得分:41)

这是获取菜单实例的技巧:

PopupMenu p  = new PopupMenu(getContext(), null);
Menu menu = p.getMenu();

答案 1 :(得分:28)

我找到了两个以编程方式创建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;
}

有了菜单实例后,您可以轻松地从程序中的菜单XML资源任何地方中对其进行充气

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

我测试了两种方法并且它们运行良好,我建议使用第二种方法,使用android SDK 中的标准MenuMenuItem类,即使您的活动扩展了SherlockActivity 因为无论你使用onOptionsItemSelected(MenuItem item)还是android.view.MenuItem

点击它,它都会收到com.actionbarsherlock.view.MenuItem

答案 2 :(得分: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;
}

添加方法中的第二个参数是id。使用唯一的 ids 标识您选择的菜单项。

答案 3 :(得分:1)

我不确定为什么这还不是答案,我知道这是一个老问题,但对于将来的读者来说。

如果您只是这样做:

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

有效!

MenuBuilder最终扩展了android.view.Menu。经检查,这就是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)

        ...
    }
}

答案 4 :(得分:0)

您可以拉出存储在PhoneWindow中的MenuBuilder(实现Menu界面)的实例,该实例正在Activity中使用。我有一个有效的解决方案,它使用Java Reflection。

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

BR, Prasanta