How to create a Menu instance programmatically? i.e. inflate a Menu outside onCreateOptionsMenu

只谈情不闲聊 提交于 2019-12-09 04:12:04

问题


I want to inflate a menu object outside onCreateOptionsMenu method (which means to create/show the menu when the user doesn't press the button), so I need to create a menu instance to pass it to the inflate method.

Here is an example of what I am trying to achieve:

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

Menu is an interface, so I need to know which class is implementing it. I did browse Android code to get any hint on how a Menu object is created, but still could not find what I am looking for.

Edit 1

My goal is to fire an onOptionsItemSelected(MenuItem item) event from a custom view, which will be handled by the activity, so I need to have a MenuItem object with specific itemId and title to pass it with the event.

If I can successfully create a Menu object, it will be easy to get its children MenuItems.

Edit 2

I am not trying to display a menu at all, what I want is to populate a ListView with elements defined in a menu XML that have title, icon and itemId and whenever a ListViewItem is clicked I want to fire a onOptionsItemSelected(MenuItem item) event that is handled in my activity.

I know that I can parse the menu XML to extract items information, however I will not be able to fire onOptionsItemSelected(MenuItem item) without creating a standard MenuItem object to pass it as argument.

Any help will be appreciated. Thanks!


回答1:


Here's a trick to get an instance of Menu:

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



回答2:


I found two solutions to programmatically create a Menu instance and inflate it:

  • Using ActionbarSherlock library or AppCompat v7 library Menu menu = new MenuBuilder(context); or you can write your own MenuBuilder class

  • Using standard android SDK:

// Creating an instance by reflection

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;
}

Once you have a Menu instance you can easily inflate it from a menu XML resource anywhere in your program

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

I tested both methods and they are working perfectly, I would recommend using the second method with the standard Menu and MenuItem classes from android SDK even if your activity extends SherlockActivity because it will still receive onOptionsItemSelected(MenuItem item) regardless if you fire it with android.view.MenuItem or com.actionbarsherlock.view.MenuItem




回答3:


You dont need to do anything with inflator in order to add your own menus. Simply override onCreateOptionsMenu and start adding your own items in the menu object. For example:

@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;
}

The second argument in add method is the id. Use unique ids to identify your selected menu item.




回答4:


I'm not sure why this isn't an answer already, and I know this is an old question, but for future readers..

If you simply do this:

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

It works!

MenuBuilder eventually extends android.view.Menu. Upon inspection, that's all that PopupMenu does.

Here are two helper functions and a usage example:

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) }
}

Usage:

Activity

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

    val menu by inflateMenu(R.menu.menu_my)

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

        ...
    }
}

Fragment:

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)

        ...
    }
}



回答5:


You can pull instance of MenuBuilder (which implements Menu interface) stored in PhoneWindow which is being used in Activity. I have an working solution, it uses Java Reflection.

I have created one project "InDroid" to expose few important hidden methods, variables from Android platform- http://code.google.com/p/indroid/

BR, Prasanta



来源:https://stackoverflow.com/questions/14118820/how-to-create-a-menu-instance-programmatically-i-e-inflate-a-menu-outside-oncr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!