How to display submenu from PopupMenu without Dismissing Android - android

I have Java show popup menu function and xml below It work, but I want to display both Min menu and sub menu when user click on main Item.
For example When user Click on Price display child of price, and don't hide the main like price or type of product..., and if click type of product display child of type of product but don't hide main.
Here the result I expect to be.
Show popup menu java
//Filter Menu
public void showPopupMenu(View view) {
// inflate menu
android.widget.PopupMenu popup = new PopupMenu(getApplicationContext(), view);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.dailydeal_filter, popup.getMenu());
//popup.setOnMenuItemClickListener(new MyMenuItemClickListener());
popup.show();
}
Here is my xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/category"
android:title="Price">
<menu>
<item android:title="Price From 10-100"></item>
<item android:title="Price From 100-200"></item>
<item android:title="Price From 200-300"></item>
<item android:title="Price Higher then 300"></item>
</menu>
</item>
<item android:id="#+id/type_product"
android:title="Type Product">
<menu>
<item android:title="Buy Sale"></item>
<item android:title="Business Directory"></item>
</menu>
</item>
</menu>

Related

How can we change the width of PopupMenu, and center the text?

I'm having a hard time in android studio.
I want the width changed to match the text size in PopupMenu, and the text to be centered.
In activity, PopupMenu used :
Context wrapper = new ContextThemeWrapper(PatientListActivity.this, R.style.YOURSTYLE);
PopupMenu popupMenu = new PopupMenu(wrapper, typeView);
popupMenu.getMenuInflater().inflate(R.menu.menu_type, popupMenu.getMenu());
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
And my PopupMenu's menu item is :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/item_all"
android:title="All"/>
<item android:id="#+id/item_p"
android:title="P"/>
<item android:id="#+id/item_et"
android:title="ET"/>
<item android:id="#+id/item_no"
android:title="ㅡ"/>
</menu>
I specified PopupMenu's style like this, but nothing changed.
<style name="YOURSTYLE" parent="Widget.AppCompat.PopupMenu">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_gravity">center_horizontal</item>
</style>
I hope that the width size in PopupMenu can be changed, and the text can be arranged in the center.

¿Change text color main menu android?

I want to change the color of the text of an item that groups a menu.
The xml file:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_mi_cuenta"
android:icon="#mipmap/ic_mi_cuenta"
android:title="#string/mi_cuenta" />
</group>
<item android:title="#string/herramientas">
<menu>
<item
android:id="#+id/nav_configuracion"
android:icon="#mipmap/ic_config"
android:title="#string/configuraci_n" />
</menu>
</item>
</menu>
I wnat to change text color of:
<item android:title="#string/herramientas">
As you can see, Herramientas comes out in black and as the background is also black it barely looks. I can not find any property to change it. The color of the item 'Mis datos' and 'Configuración' change it programmatically as follows from an external json file of a server:
colorElegido = getParseColor(json.getString("colorMenuLateral"));
navigationView.setBackgroundColor(colorElegido);
colorElegido = getParseColor(json.getString("colorFuenteMenuLateral"));
ColorStateList colorList = getColorList(colorElegido);
navigationView.setItemTextColor(colorList);
The following code will workout,
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_mi_cuenta"
android:icon="#mipmap/ic_mi_cuenta"
android:title="#string/mi_cuenta" />
</group>
<item
android:id="#+id/herramientas"
android:title="#string/herramientas">
<menu>
<item
android:id="#+id/nav_configuracion"
android:icon="#mipmap/ic_config"
android:title="#string/configuraci_n" />
</menu>
</item>
</menu>
Add this in your styles,
<style name="TextAppearance44">
<item name="android:textColor">#FF0000</item>
<item name="android:textSize">20sp</item>
</style>
<style name="NavigationDrawerStyle">
<item name="android:textSize">16sp</item><!-- text size in menu-->
<item name="android:textColor">#880ACE0A</item>
<item name="itemTextColor">#880ACE0A</item>
</style>
And in your activity,
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
Menu menu = navigationView.getMenu();
MenuItem tools= menu.findItem(R.id.herramientas);
SpannableString s = new SpannableString(tools.getTitle());
s.setSpan(new TextAppearanceSpan(this, R.style.TextAppearance44), 0, s.length(), 0);
tools.setTitle(s);
navigationView.setNavigationItemSelectedListener(this);
Change according to you,
And other text color change you can use like in your xml file,
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
style="#style/NavigationDrawerStyle"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
to make a custom popup make an ImageView in toolbar
private ImageView setting;
public void menuOptions() {
PopupMenu popup = new PopupMenu(MainActivity.this, setting);
// Inflating the Popup using xml file
popup.getMenuInflater()
.inflate(R.menu.menu_main, popup.getMenu());
//registering popup with OnMenuItemClickListener
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.button1:
return (true);
case R.id.button2:
// block contacts
return (true);
}
return true;
}
});
popup.show(); //showing popup menu
}
on Button click call above function
menuOptions();
in the layout you inflate menu_main.xml, make your desired view.

MenuPopupHelper cannot be used without an anchor

I want add PopupMenu to my MenuItem.
Menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/date"
app:showAsAction="ifRoom|withText"
android:title="Date"
android:visible="true"/>
<item
android:id="#+id/category"
app:showAsAction="ifRoom|withText"
android:title="Category"
android:visible="true"/>
</menu>
When I click on MenuItem I call this code:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.filter_action) {
showPopup(item.getActionView());
}
return super.onOptionsItemSelected(item);
}
private void showPopup(View v) {
PopupMenu popup = new PopupMenu(getActivity(), v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.filter_billing_menu, popup.getMenu());
popup.show();
}
And I get this exception:
java.lang.IllegalStateException: MenuPopupHelper cannot be used without an anchor
How I can fix it?
I'm reading "internet" and I try this code:
showPopu(getActivity().findViewById(R.id.filter_action));
Instead
showPopup(item.getActionView());
It's works for me
I believe a better (and simpler) approach in this case would be to define a submenu instead of creating a PopupMenu.
For example:
<item android:id="#+id/menu"
android:title="menu" >
<menu>
<item android:id="#+id/item_in_submenu_1"
android:title="subitem1" />
<item android:id="#+id/item_in_submenu_2"
android:title="subitem2" />
</menu>
</item>
My problem was that I had
<item android:id="#+id/menu_entry_to_show_popupmenu"
app:showAsAction="ifRoom" />
and what I needed is
<item android:id="#+id/menu_entry_to_show_popupmenu"
app:showAsAction="always" />
showAsAction="always" is needed. A menu entry hidden in the three dots (overflow menu) can't have a popupmenu anchored to it.
My full popupmenu setup function begins like this:
PopupMenu popup = new PopupMenu(getActivity(), getActivity().findViewById(R.id.menu_filter));
popup.getMenuInflater().inflate(R.menu.filter_tasks, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
[...]
popup.show();
}
Change your this code:
app:showAsAction="ifRoom|withText"
to this:
android:showAsAction="ifRoom|withText"

Android actionbar submenu items displayed on top of the actionbar instead of below the bar

I need to show the submenu below the bar, not on top of the bar itself.
Copying my actionbar xml below
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item
android:id="#+id/action_pages"
android:orderInCategory="1"
android:showAsAction="withText|always"
android:icon="#drawable/ic_action_pages"
android:title="">
<menu>
<item android:id="#+id/item1" android:title="Placeholder"></item>
</menu>
</item>
</menu>
In the activity (App also has a navigation drawer)
public boolean onCreateOptionsMenu(Menu menu) {
if (!mNavigationDrawerFragment.isDrawerOpen()) {
getMenuInflater().inflate(R.menu.main, menu);
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
Simply.
<style name="AppTheme" parent="AppBaseTheme">
<item name="actionOverflowMenuStyle">#style/OverflowMenu</item>
</style>
<style name="OverflowMenu" parent="Widget.AppCompat.PopupMenu.Overflow">
<!-- Required for pre-Lollipop. -->
<item name="overlapAnchor">false</item>
<!-- Required for Lollipop. -->
<item name="android:overlapAnchor">false</item>
</style>
Preamble
As usual, I faced a strange problem while developing an Android app, tried to find a solution and landed to this question. As it was in many cases before, there is no an answer. So I was compelled to solve the problem from scratch and now posting the answer with my workaround.
Input
I have an Android app with action bar and some menu items, which have to be extended with dropdown submenu. First attempt was to implement it as suggested by Android documentation. So I added new menu item menu_sort into existing action bar menu and sub-menu container into it:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#+id/id1" android:icon="#drawable/ic_1"
android:title="#string/id1" android:showAsAction="withText|always"/>
...
<item
android:id="#+id/menu_sort"
android:icon="#drawable/ic_menu_sort_selector"
android:title="▾"
android:titleCondensed="▾"
android:showAsAction="withText|always">
<menu>
<item
android:id="#+id/menu_sort_by_name"
android:showAsAction="never"
android:checkable="true"
android:checked="true"
android:title="#string/sort_by_name"/>
<item
android:id="#+id/menu_sort_by_priority"
android:showAsAction="never"
android:checkable="true"
android:checked="false"
android:title="#string/sort_by_priority"/>
<item
android:id="#+id/menu_sort_by_memory"
android:showAsAction="never"
android:checkable="true"
android:checked="false"
android:title="#string/sort_by_memory"/>
</menu>
</item>
</menu>
Result
The effect was exactly as described in the question: the submenu is displayed on top of the action bar. Here is the screenshot taken on Android 5.1.1:
I played with many options and code snippets - nothing helped. Finally I came to the following
Solution
First, move all the submenu into a separate menu layout, say, menu/sorting.xml, and remove it from menu_sort item of the main menu (shown above).
Second, modify or create onPrepareOptionsMenu event handler with the following code:
#Override
public boolean onPrepareOptionsMenu(Menu menu)
{
// as solution utilizes PopupMenu,
// take care about older Android versions if necessry
// if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
// here goes most crazy part: we use menu id
// to retrieve corresponding view, automatically created by OS;
// imho, this is a hack, and menu item should have getView() method or similar;
View menuItemView = findViewById(R.id.menu_sort);
// by the way, menuItemView could probably be null under some circumstances
// create a popup anchored to the view (menu item)
final PopupMenu popupMenu = new PopupMenu(this, menuItemView);
// API 14
// popupMenu.inflate(R.menu.sorting);
// API 11 (HONEYCOMB)
popupMenu.getMenuInflater().inflate(R.menu.sorting, popupMenu.getMenu());
// process popup clicks as appropriate
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener()
{
#Override
public boolean onMenuItemClick(MenuItem item)
{
switch(item.getItemId())
{
// ... place some code
}
return true;
}
});
// bind the popup to the item menu
menu.findItem(R.id.menu_sort).setOnMenuItemClickListener(new OnMenuItemClickListener()
{
#Override
public boolean onMenuItemClick(MenuItem item)
{
popupMenu.show();
return true;
}
});
return super.onPrepareOptionsMenu(menu);
}
Here is the result:
Now the dropdown is displayed as expected from very beginning.
#Stan's solution doesn't work for me, so here's my way to implement sub-menu on top of ActionBar (but below the main-menu of course):
I've created 2 xml files: menu_main.xml and menu_more.xml located in res/menu directory
The first one 'menu_main.xml' contain the menu:
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- our addMenu doesn't have sub-items-->
<item
android:id="#+id/action_add"
android:icon="#drawable/ic_note_add_white_24dp"
android:title="#string/action_add"
app:showAsAction="ifRoom"/>
<!-- our moreMenu which show drop-down menu when clicked-->
<item
android:id="#+id/action_more"
android:icon="#drawable/ic_more_vert_white_24dp"
android:title="#string/action_more" <!--in text: "more"-->
app:showAsAction="always"/>
</menu>
And the second one 'menu_more.xml' contain the drop-down menu:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- This menu will be hidden by default-->
<!-- But will be visible when moreMenu with '#+id/action_more' is clicked-->
<item
android:id="#+id/action_settings"
app:showAsAction="ifRoom|withText"
android:title="#string/action_settings" <!-- In text: "Settings"-->
android:visible="true"/>
</menu>
Here is what previous menus look like:
result-after-add-2-xmls (i have not enough 10 reputation to display image)
In the activity, i've overridden this method:
public boolean onPrepareOptionsMenu(Menu menu)
In the previous method, i get reference to the main menuItem (in this case is menu with #+id/action_more located in menu_main.xml file), then set setOnMenuItemClickListener on it and finally, declare and set up a PopupMenu instance to manage and display sub-menu items:
// show popup menu when menuMore clicked
menu.findItem(R.id.action_more).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener()
{
#Override
public boolean onMenuItemClick(MenuItem item)
{
// get reference to menuMore item
View menuMore = findViewById(item.getItemId());
// create a popup anchored to the view (menuMore)
// notes: if declare and set up PopupMenu Outside of this onMenuItemClick()
// then it'll not work!
// Because: the view you put into PopupMenu() could be null
final PopupMenu popupMenu = new PopupMenu(getApplicationContext(), menuMore);
// inflate 'menu_more.xml' layout file
// which contain all sub-items of menu
popupMenu.getMenuInflater().inflate(R.menu.menu_more, popupMenu.getMenu());
// process popup clicks on sub-items
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener()
{
#Override
public boolean onMenuItemClick(MenuItem item)
{
switch(item.getItemId()){
case R.id.action_settings:
Toast.makeText(getApplicationContext(), "showing SettingsActivity..",
Toast.LENGTH_SHORT).show();
break;
// more items go here
}
return true;
}
});
popupMenu.show();
return true;
}
});
return super.onPrepareOptionsMenu(menu);
And here is final result:
final-look-drop-down-menu

Android adding a submenu to a menuItem, where is addSubMenu()?

I want to add a submenu inside my OptionsMenu to a menuItem, programatically according to my parameters. I've checked "MenuItem" in android sdk and there is no addSubMenu() method!, although you can find "hasSubMenu()" and "getSubMenu".
Was thinking on doing this in onCreateOptionsMenu:
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem mi = menu.getItem(MYITEMID); // << this is defined in my XML optionsMenu
SubMenu subm = mi.addSubMenu(0,1,0,"Map 1"); // no addSubMenu() method!!!???
....
How do I create a submenu inside a menuitem in code?
Sometimes Android weirdness is really amazing (and amusing..). I solved it this way:
a) Define in XML a submenu placeholder like this:
<item android:visible="true" android:id="#+id/m_area"
android:titleCondensed="Areas"
android:title="Areas"
android:icon="#drawable/restaur"
android:enabled="true">
<menu>
<item android:id="#+id/item1" android:title="Placeholder"></item>
</menu>
</item>
b) Get sub menu item in OnCreateOptionsMenu, clear it and add my submenu items, like this:
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mapoptions, menu);
int idx=0;
SubMenu subm = menu.getItem(MYITEM_INDEX).getSubMenu(); // get my MenuItem with placeholder submenu
subm.clear(); // delete place holder
while(true)
{
anarea = m_areas.GetArea(idx); // get a new area, return null if no more areas
if(anarea == null)
break;
subm.add(0, SUBAREASID+idx, idx, anarea.GetName()); // id is idx+ my constant
++idx;
}
}
I know this is an old question, but I just came across this problem myself.
The most straightforward way of doing this, seems to be to simply specify the item itself as a submenu, then add to this item.
E.g.:
menu.add(groupId, MENU_VIEW, Menu.NONE, getText(R.string.menu_view));
menu.add(groupId, MENU_EDIT, Menu.NONE, getText(R.string.menu_edit));
SubMenu sub=menu.addSubMenu(groupId, MENU_SORT, Menu.NONE, getText(R.string.menu_sort));
sub.add(groupId, MENU_SORT_BY_NAME, Menu.NONE, getText(R.string.menu_sort_by_name));
sub.add(groupId, MENU_SORT_BY_ADDRESS, Menu.NONE, getText(R.string.menu_sort_by_address));
:
:
Here's a complete answer which builds on the idea of using a placeholder but uses mostly xml to add the submenu.
If you have a menu like so called main_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="My Menu"
android:id="#+id/my_menu_item">
<!-- A empty SubMenu -->
<menu></menu>
</item>
</menu>
Create another menu sub_menu.xml which will be used in my_menu_item:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="SubMenu One"
android:id="#+id/submenu_one" />
<item android:title="SubMenu Two"
android:id="#+id/submenu_two" />
<item android:title="SubMenu Three"
android:id="#+id/submenu_three" />
</menu>
In your onCreateOptionsMenu:
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate your main_menu into the menu
getMenuInflater().inflate(R.menu.main_menu, menu);
// Find the menuItem to add your SubMenu
MenuItem myMenuItem = menu.findItem(R.id.my_menu_item);
// Inflating the sub_menu menu this way, will add its menu items
// to the empty SubMenu you created in the xml
getMenuInflater().inflate(R.menu.sub_menu, myMenuItem.getSubMenu());
}
This solution is nice since the inflater handles most of the work.
The best way to do this is in your xml menu file. You can do this by creating a new menu object inside of an item:
<menu>
<item>
...
<menu>
...
</menu>
...
</item>
</menu>
To provide a comprehensive example of Phil's answer, here is my complete, working XML for a menu with two choices, each of which is a menu with three choices. I intend to add a third menu to the top level ...
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:HTMLCode="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/Examine"
android:title="#string/Examine"
HTMLCode:showAsAction="always">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:HTMLCode="http://schemas.android.com/apk/res-auto" >
<item android:id="#+id/load"
android:title="#string/load"
HTMLCode:showAsAction="ifRoom|withText" />
<item android:id="#+id/findfirst"
android:title="#string/findfirst"
HTMLCode:showAsAction="ifRoom|withText" />
<item android:id="#+id/findnext"
android:title="#string/FindNext"
HTMLCode:showAsAction="ifRoom|withText" />
</menu>
</item>
<item android:id="#+id/Redirect"
android:title="#string/Redirect"
HTMLCode:showAsAction="ifRoom|withText">
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:HTMLCode="http://schemas.android.com/apk/res-auto" >
<item android:id="#+id/getRedirect"
android:title="#string/getRedirect"
HTMLCode:showAsAction="ifRoom|withText" />
<item android:id="#+id/toggleRedirect"
android:title="#string/toggleRedirect"
HTMLCode:showAsAction="ifRoom|withText" />
<item android:id="#+id/copyRedirect"
android:title="#string/copyRedirect"
HTMLCode:showAsAction="ifRoom|withText" />
</menu>
</item>
</menu>
You should consider use a ActionProvider instead.
public class MyActionProvider extends ActionProvider {
private Context mContext;
public MyActionProvider(Context context) {
super(context);
mContext = context;
}
#Override
public View onCreateActionView() {
//LayoutInflater layoutInflater = LayoutInflater.from(mContext);
return null;
}
#Override
public void onPrepareSubMenu(SubMenu subMenu) {
super.onPrepareSubMenu(subMenu);
subMenu.clear();
subMenu.add("menu 1");
subMenu.add("menu 2");
subMenu.add("menu 3");
}
#Override
public boolean hasSubMenu() {
return true;
}
#Override
public boolean onPerformDefaultAction() {
return super.onPerformDefaultAction();
}
}
I would just create the submenu in xml file, and in run time get the submenu from menu object, (using findItem(id) method) and use submenu.setVisible(boolean) to add/remove it on run time.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/menu1" android:alphabeticShortcut="a"
android:title="Menu No. 1" android:orderInCategory="1" />
<item android:id="#+id/menu2" android:alphabeticShortcut="b"
android:title="Menu No. 2" android:orderInCategory="2">
<menu >
<group android:id="#+id/group2" android:checkableBehavior="single">
<item android:id="#+id/submenu1" android:title="SubMenu No. 1" />
<item android:id="#+id/submenu2" android:title="SubMenu No. 2" />
</group>
</menu>
</item>

Categories

Resources