android how to put sub-menu within submenu - android

I want to add a submenu to an existing submenu with this xml:
<item android:id="#+id/chooseCountry" android:title="Choose Country">
<menu>
<item android:id="#+id/india" android:title="India" >
<menu>
<item android:id="#+id/blor" android:title="Bangalore" />
<item android:id="#+id/delhi" android:title="Delhi" />
<item android:id="#+id/hyd" android:title="Hyderabad" />
</menu>
</item>
<item android:id="#+id/pak" android:title="Pakistan" />
<item android:id="#+id/africa" android:title="South Africa" />
</menu>
</item>
I am getting but this exception:
08-15 12:57:50.942: ERROR/AndroidRuntime(312): java.lang.UnsupportedOperationException: Attempt to add a sub-menu to a sub-menu.
I do not understand what I am doing wrong - can anybody give me some advice?

This appears to be natively supported from Android API level 15. On earlier versions, a workaround is to redirect menu calls. Using your xml example, change it so that the sub-sub-menu is a regular hidden menu item, and add a redirect place holder item instead:
<item android:id="#+id/india" android:title="India" android:visible="false">
<menu>
<item android:id="#+id/blor" android:title="Bangalore" />
<item android:id="#+id/delhi" android:title="Delhi" />
<item android:id="#+id/hyd" android:title="Hyderabad" />
</menu>
</item>
<item android:id="#+id/chooseCountry" android:title="Choose Country">
<menu>
<item android:id="#+id/india_redirect" android:title="India" />
<item android:id="#+id/pak" android:title="Pakistan" />
<item android:id="#+id/africa" android:title="South Africa" />
</menu>
Hang on to the inflated Menu mOptionsMenu created in onCreateOptionsMenu( Menu menu ) and open the sub-menu from your redirect like this:
#Override
public boolean onMenuItemSelected( int id, MenuItem item)
{
switch ( item.getItemId() )
{
case R.id.india_redirect:
mSomeView.post( new Runnable()
{
public void run()
{
mOptionsMenu.performIdentifierAction( R.id.india, 0 );
}
} );
return true;
}
return super.onMenuItemSelected( id, item );
}
Note the call to performIdentifierAction is posted from a View to the UI message queue. On old versions of Android it can be called immediately, but on newer versions it needs to be a separate message to work.

Well, apparently this is not supported. You'll have to redesign your menu.

Related

onCreateOptionsMenu crashes only on Oreo

EDIT: Problem solved after upgrading Build Tools Version from 23 to 27.
I have the following code snippet:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.findItem(R.id.shareMenuItem).getActionView().setOnClickListener(onShareMenuItemClickedListener);
}
Recently I have got some errors on Crashlytics with line menu.findItem(...):
Fatal Exception: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.View android.view.MenuItem.getActionView()' on a null object reference
at pl.application.ProductViewFragment.onCreateOptionsMenu(SourceFile:434)
at android.support.v4.app.Fragment.performCreateOptionsMenu(SourceFile:2186)
at android.support.v4.app.FragmentManagerImpl.dispatchCreateOptionsMenu(SourceFile:2250)
at android.support.v4.app.FragmentController.dispatchCreateOptionsMenu(SourceFile:328)
at android.support.v4.app.FragmentActivity.onCreatePanelMenu(SourceFile:363)
The problem is not deterministic and shows only on Android Oreo (by Fabric - 100% of crashes were on Android 8.0, different devices). I have never had problems with this line before.
Were there any important changes in Android 8.0 able to cause NPE there? I've tried reproduce it on my Xiaomi Mi A1, but with no effects. Or maybe there is a workaround?
Thanks!
// Edit: added xml menu file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:res="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/breadcrumbsMenuItem"
android:icon="#drawable/ic_breadcrumbs"
android:title="#string/breadcrumbs"
res:showAsAction="always" />
<item
android:id="#+id/shareMenuItem"
android:icon="#drawable/ic_menu_share"
android:title="#string/share"
res:actionLayout="#layout/layout_share_button"
res:showAsAction="always" />
</menu>
Just try to add something like this, to see if it will be still null or not
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
public void run()
{
menu.findItem(R.id.shareMenuItem).getActionView().setOnClickListener(onShareMenuItemClickedListener);
}
}, 2000);
If this fixes the problem, then the reason for him to be null is that is still hasn't been created and you area all rdy trying to access to it
I did have a problem when I was trying to change the color of an icon of my Menu acording to some info that it get's when the program starts, and that "work arround" fix the problem to me
I'm not sure where you get res:... but i think it should be app:...
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:res="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/breadcrumbsMenuItem"
android:icon="#drawable/ic_breadcrumbs"
android:title="#string/breadcrumbs"
app:showAsAction="always" />
<item
android:id="#+id/shareMenuItem"
android:icon="#drawable/ic_menu_share"
android:title="#string/share"
app:actionLayout="#layout/layout_share_button"
app:showAsAction="always" />
</menu>

android-Popup menu onitemclick error

I'm trying direct each popup menu item to the another activity by using intent,but i get an error shown below:
This is my java code of popup menu:
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.one:
Intent i = new Intent(Cihazlar.this,MainActivity.class);
startActivity(i);
return true;
case R.id.two:
Intent i2 = new Intent(Cihazlar.this,Kampanya.class);
startActivity(i2);
return true;
}
return true;
}
});
And this is popup menu xml:
<menu xmlns:androclass="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/tools">
<item
android:id="#+id/one"
androclass:title="Senin Dünyan" />
<item
android:id="#+id/two"
androclass:title="Destek" />
<item
android:id="#+id/three"
androclass:title="Sıkça Sorulan Sorular" />
So why am i getting this error? Any help will be appreciated.
the problem is not at run time. It's compile time error. So if error is like resource not found then error is while importing R package or error in menu.xml.
But menu.xml looks proper, so I think, main problem is with R.java import. Check you have not imported com.android.R. It should be your <package_name>.R.
And even if this is ok, then your resources are not compiled completely. There might be some error at some other resource file (.xml file)
The very last thing one can try is to rebuild your app and then check out
EDIT
I think error is in menu.xml file itself. Try below code, unless you have made some customize stuff-
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/one"
android:title="Senin Dünyan" />
<item
android:id="#+id/two"
androclass:title="Destek" />
<item
android:id="#+id/three"
android:title="Sıkça Sorulan Sorular" />
bro have u declared it in Manifest plz post your manifest code

How to use notifyDataSetChanged with the new NavigationView?

I use the new NavigationView in one of my recent projects. However I have a problem for the update data.
Previously, I used a ListView in my DrawerLayout and when I needed to change my data I called notifyDataSetChanged() method of my Adapter.
Currently NavigationView does not notifyDataSetChanged() method and when I want to update an item on my menu nothing is happening, for example:
Menu menuAccount = navigationView.getMenu().findItem(R.id.drawer_item_account).getSubMenu();
menuAccount.findItem(R.id.drawer_item_login).setVisible(!isLoggedIn);
Do you have a solution ? Thanks you for your help.
UPDATE: This was fixed in v23.0.0 so you don't need to do anything by youself, just update your dependency. Got from this answer: https://stackoverflow.com/a/32181083/2489474
Old solution (just to see how stupid it could be):
But I've found working solution in this answer https://stackoverflow.com/a/30604299/2489474. It uses reflection to call updateMenuView(boolean) of NavigationView's presenter.
I've modified code from the answer for my purposes. Check also a method from the answer and choose which one is better for you.
//HACK
private void updateNavigationView() {
try {
Field presenterField = NavigationView.class.getDeclaredField("mPresenter");
presenterField.setAccessible(true);
((NavigationMenuPresenter) presenterField.get(navigationView_)).updateMenuView(false);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
P.S. it is interesting that updateMenuView ignores a value was given to it.
#Moinkhan Thanks you for your helper but doesn't work for me. Here my menu_drawer.xml
<group
android:checkableBehavior="single"
android:id="#+id/group1">
<item
android:id="#+id/drawer_item_publications_list"
android:icon="#drawable/ic_drawer_publications_24dp"
android:title="#string/drawer_menu_item_publications" />
</group>
<group android:id="#+id/drawer_group_account">
<item
android:title="#string/drawer_menu_sub_item_account"
android:id="#+id/drawer_item_account">
<menu>
<item
android:icon="#drawable/ic_drawer_login_24dp"
android:id="#+id/drawer_item_login"
android:title="#string/drawer_menu_item_login" />
<group
android:id="#+id/group_actions_user">
<item
android:icon="#drawable/ic_drawer_add_publication_24dp"
android:id="#+id/drawer_item_add_publication"
android:title="#string/drawer_menu_item_add_publication" />
<item
android:icon="#drawable/ic_drawer_my_publications_24dp"
android:id="#+id/drawer_item_my_publications"
android:title="#string/drawer_menu_item_my_publications" />
<item
android:icon="#drawable/ic_drawer_edit_profil_24dp"
android:id="#+id/drawer_item_edit_profil"
android:title="#string/drawer_menu_item_edit_profil" />
<item
android:icon="#drawable/ic_drawer_delete_account_24dp"
android:id="#+id/drawer_item_delete_account"
android:title="#string/drawer_menu_item_delete_account" />
<item
android:icon="#drawable/ic_drawer_logout_24dp"
android:id="#+id/drawer_item_logout"
android:title="#string/drawer_menu_item_logout" />
</group>
</menu>
</item>
</group>
And my method to update my NavigationView
private void setUpNavigationDrawer()
{
boolean isLoggedIn = sessionManager.isLoggedIn();
navigationView.getMenu().findItem(R.id.drawer_item_account).getSubMenu().findItem(R.id.drawer_item_login).setVisible(!isLoggedIn);
navigationView.getMenu().findItem(R.id.drawer_item_account).getSubMenu().setGroupVisible(R.id.group_actions_user, isLoggedIn);
}
After some operations I called setUpNavigationDrawer() but the menu was not updated !
Instead of referencing group and then finding a item from that group and setting it's visibility try to reference the item directly like this ...
navView.getMenu().findItem(R.id.drawer_item_login).setVisible(!isLoggedin);
navView.getMenu().findItem(R.id.drawer_item_account).getSubMenu().setGroupVisible(R.id.group_actions_user, !isLoggedin);
It works for me. I hope it helps you.

How to create custom option menu in android

I am creating an option menu. it has three option HOME, EMAIL, VISIT. All three options coming at the same row. i have to show HOME option above and rest two below to Home Option(according to attached Screen Shot).
Any Ideas??
Thanks.
Here is my XML file.
<menu android:id="#+id/new_game"
android:icon="#drawable/red_no_bg"
android:title="Home" />
<item android:id="#+id/email"
android:icon="#drawable/red_no_bg"
android:title="Email" />
<item android:id="#+id/help"
android:icon="#drawable/red_no_bg"
android:title="Visit Microsite" />
</menu>
Here is my code.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.layout.overview_menu, menu);
return true;
}
Using the above code i am getting the all option in Same line.
You can Create in two ways
1.Statically.
2.Dynamically.
Am explaining the easiest method of adding menus.
Step 1: Create a new Android Application.
Step 2: After onCreate() method write onCreateOptionMenu();
Step 3: In onCreateOptionMenu() Write these lines
menu.add(11, 21, 1, "Gowtham").setIcon(R.drawable.ic_launcher);
Here "Gowtham" is title of your menu item You can Home&Email use instead of "Gowtham".
Ans use Any images Instead of ic.launcher

How to add a custom button state

For instance, the default button has the following dependencies between its states and background images:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true"
android:drawable="#drawable/btn_default_normal" />
<item android:state_window_focused="false" android:state_enabled="false"
android:drawable="#drawable/btn_default_normal_disable" />
<item android:state_pressed="true"
android:drawable="#drawable/btn_default_pressed" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="#drawable/btn_default_selected" />
<item android:state_enabled="true"
android:drawable="#drawable/btn_default_normal" />
<item android:state_focused="true"
android:drawable="#drawable/btn_default_normal_disable_focused" />
<item
android:drawable="#drawable/btn_default_normal_disable" />
</selector>
How can I define my own custom state (smth like android:state_custom), so then I could use it to dynamically change my button visual appearance?
The solution indicated by #(Ted Hopp) works, but needs a little correction: in the selector, the item states need an "app:" prefix, otherwise the inflater won't recognise the namespace correctly, and will fail silently; at least this is what happens to me.
Allow me to report here the whole solution, with some more details:
First, create file "res/values/attrs.xml":
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="food">
<attr name="state_fried" format="boolean" />
<attr name="state_baked" format="boolean" />
</declare-styleable>
</resources>
Then define your custom class. For instance, it may be a class "FoodButton", derived from class "Button". You will have to implement a constructor; implement this one, which seems to be the one used by the inflater:
public FoodButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
On top of the derived class:
private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};
Also, your state variables:
private boolean mIsFried = false;
private boolean mIsBaked = false;
And a couple of setters:
public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}
Then override function "onCreateDrawableState":
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
if (mIsFried) {
mergeDrawableStates(drawableState, STATE_FRIED);
}
if (mIsBaked) {
mergeDrawableStates(drawableState, STATE_BAKED);
}
return drawableState;
}
Finally, the most delicate piece of this puzzle; the selector defining the StateListDrawable that you will use as a background for your widget. This is file "res/drawable/food_button.xml":
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.mydomain.mypackage">
<item
app:state_baked="true"
app:state_fried="false"
android:drawable="#drawable/item_baked" />
<item
app:state_baked="false"
app:state_fried="true"
android:drawable="#drawable/item_fried" />
<item
app:state_baked="true"
app:state_fried="true"
android:drawable="#drawable/item_overcooked" />
<item
app:state_baked="false"
app:state_fried="false"
android:drawable="#drawable/item_raw" />
</selector>
Notice the "app:" prefix, whereas with standard android states you would have used prefix "android:". The XML namespace is crucial for a correct interpretation by the inflater and depends on the type of project in which you are adding attributes. If it is an application, replace com.mydomain.mypackage with the actual package name of your application (application name excluded). If it is a library you must use "http://schemas.android.com/apk/res-auto" (and be using Tools R17 or later) or you will get runtime errors.
A couple of notes:
It seems you don't need to call the "refreshDrawableState" function, at least the solution works well as is, in my case
In order to use your custom class in a layout xml file, you will have to specify the fully qualified name (e.g. com.mydomain.mypackage.FoodButton)
You can as weel mix-up standard states (e.g. android:pressed, android:enabled, android:selected) with custom states, in order to represent more complicated state combinations
This thread shows how to add custom states to buttons and the like. (If you can't see the new Google groups in your browser, there's a copy of the thread here.)
Please do not forget to call refreshDrawableState within UI thread:
mHandler.post(new Runnable() {
#Override
public void run() {
refreshDrawableState();
}
});
It took lot of my time to figure out why my button is not changing its state even though everything looks right.

Categories

Resources