How to create a Menu instance programmatically? i.e. inflate a Menu outside onCreateOptionsMenu
Here's a trick to get an instance of Menu:
PopupMenu p = new PopupMenu(getContext(), null);
Menu menu = p.getMenu();
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 ownMenuBuilder
classUsing 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
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!
androidx.appcompat.view.menu.MenuBuilder
implements android.view.Menu
. Upon inspection, that's all that PopupMenu
does.
Note that the com.android.internal.view.menu.MenuBuilder
mentioned by @iTech and used by PopupMenu
is not public and should not be used.
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)
...
}
}