So I have this toolbar in my app, and I want to display different menu items depending on whether the user is logged in or not. When the user logs in or out I want to update my layout which for now is the toolbar menu to represent the change. For some reason though, my menu items are not removed at all, all of them are visible at all times, regardless of the login state.
My menu items:
<menu
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_add"
android:icon="#drawable/ic_action_add"
android:title="#string/action_add"
app:showAsAction="ifRoom"/>
<item
android:id="#+id/action_login"
android:icon="#drawable/ic_action_logged_out"
android:title="#string/action_log_in"
app:showAsAction="always"/>
<item
android:id="#+id/action_logout"
android:icon="#drawable/ic_action_logged_in"
android:title="#string/action_log_out"
app:showAsAction="always"/>
</menu>
The first menu item is only supposed to be visible to a user that is logged in. Also I guess it's self explanatory but I only want one of the log in/out buttons to be visible depending on the login state.
My Java code:
protected void initializeToolbar(){
myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
menu = myToolbar.getMenu();
resetToolbarMenu();
myToolbar.setOnMenuItemClickListener(this);
}
private void resetToolbarMenu(){
menu.clear();
getMenuInflater().inflate(R.menu.menu, menu);
if(loginPrefs.getBoolean("login", false)) { //loginPrefs is reference to a SharedPreference object
menu.removeItem(1);
} else {
menu.removeItem(2);
menu.removeItem(0);
}
}
Reason I got two methods is that I only want to set up the toolbar and listener once, but I want to be able to change the menu every time the user logs in/out without reloading the page.
After a successful login the resetToolbarMenu() method will be called again.
I suppose the menu.remove(0) does not update the UI, but I could not find another way to reach my menu object without first inflating it and then getting it from the toolbar, and I assume the inflation is what decides what items are visible. Basically, I could not find a way to remove any menu items before inflating or updating the UI in another way than inflating.
Solution:
I changed my java code into something like this:
protected void initializeToolbar(){
myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu); // Don't know if this is necessary or if returning true is prefered.
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if(loginPrefs.getBoolean("login", false)) {
menu.getItem(0).setVisible(true);
menu.getItem(1).setVisible(false);
menu.getItem(2).setVisible(true);
} else {
menu.getItem(0).setVisible(false);
menu.getItem(1).setVisible(true);
menu.getItem(2).setVisible(false);
}
return true;
}
I also had to call invalidateOptionsMenu() on logout/login to update the toolbar/menu. However onPrepareOptionsMenu() is also automatically called whenever you open the menu for items that aren't shown on the toolbar itself.
PS: OnCreateOptionsMenu and OnPrepareOptionsMenu will not be used unless you remember to setSupportActionBar(myToolbar) as I forgot.
You can create options menu by overriding onCreateOptionsMenu. You can create 2 xml and inflate either one of them depending on your logic. To force a redraw of the menu, you can call invalidateOptionsMenu.
For example
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
if (login) {
inflater.inflate(R.menu.login_menu, menu);
} else {
inflater.inflate(R.menu.logout_menu, menu);
}
return true;
}
And outside change the flag and force redraw
login = false; // or true
invalidateOptionsMenu();
You have to override onPrepareOptionsMenu in the activity to change the items in the menu.
From the documentation:
Prepare the Screen's standard options menu to be displayed. This is called right before the menu is shown, every time it is shown. You can use this method to efficiently enable/disable items or otherwise dynamically modify the contents.
So.. I'm facing a problem that has been driving me crazy for the past hours.
I have an App using the AppCompact v21 and toolbar. I also handle back navigation using:
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
In combination with the parent activity on the manifest. Which works perfect....
My problem is:
I have an activity with 3 tabs with a viewpager and I need one of the fragments to have it's own menu.
I can inflate the menu just fine but once the menu is inflated the back arrow in that fragment don't work anymore. In the other 2 fragments of the view pager the back navigation through the toolbar still works.
Inside my fragment:
// Inside onCreate...
this.setHasOptionsMenu(true);
// Later on somewhere else...
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_submit, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
// my menu logic goes here.
return true;
}
Any suggestions?
When you always return true in onOptionsItemSelected(), that means you've handled every menu item possible (including the Up button). You should instead return super.onOptionsItemSelected(item) in cases where you do not handle one of your items:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Your menu logic such as
case R.id.your_menu_item:
// Do something
return true;
default:
return super.onOptionsItemSelected(item);
}
}
I have this item in my options menu:
<item
android:id="#+id/opt_mnu_action"
android:icon="#android:drawable/ic_dialog_info"
android:orderInCategory="1"
android:showAsAction="ifRoom"
android:title="New">
</item>
The menu itself created in main FragmentActivity. I want to change this item's icon programmatically depending on the open Fragment and, obviously, have different actions when the user hits this button. I tried several things to do that, but nothing worked. The last thing I tried was this code in my Fragment's onCreateView method:
MenuItem mi = (MenuItem) view.findViewById(R.id.opt_mnu_action);
mi.setIcon(R.drawable.ico_1);
But my app crashed. So is there a way to do that?
**UPDATE**
Here's what I'm trying to do now, all in my main main FragmentActivity:
First of all I have a MenuItem action_button; in my hierarchy view. Then in my onCreateOptionsMenu method I instantiate it:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);
action_button = menu.findItem(R.id.opt_mnu_action);
return super.onCreateOptionsMenu(menu);
}
Then I created this function to change the icon according to the open tab:
public void change_action_button_icon(int tab_position)
{
switch(tab_position)
{
case 0:
action_button.setIcon(R.drawable.ico_1);
break;
case 1:
action_button.setIcon(R.drawable.ico_2);
break;
case 2:
action_button.setIcon(R.drawable.ico_3);
break;
}
invalidateOptionsMenu();
}
And I call it in my onTabSelected method:
public void onTabSelected(ActionBar.Tab tab,
FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
setTab_position(tab.getPosition());
change_action_button_icon(tab.getPosition());
}
But once I start my app - it crashes. I get NullPointerException error at this line:
action_button.setIcon(R.drawable.ico_1);
My guess - it happens because the icon change was requested before the action_button was instantiated. But I don't know how to overcome it...
Use this to get a reference to the menu item:
menu.findItem(resourceId).setIcon(drawableId);
You have to put the code to change the icon in onCreateOptionsMenu().
Please refer to my example below:
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.option_menu, menu);
if (needToChangeMenuItem){
menu.findItem(resourceId).setIcon(drawableId);
}
manageMenuIcon(menu);
needToChangeMenuItem = false;
return true;
}
public void manageMenuIcon(Menu menu){
if (bluetoothIconOn){
menu.findItem(R.id.secure_connect_scan).setIcon(R.drawable.bluetoothon);
} else
menu.findItem(R.id.secure_connect_scan).setIcon(R.drawable.bluetoothoff);
if (gpsIconOn)
menu.findItem(R.id.gps).setIcon(R.drawable.gps);
else
menu.findItem(R.id.gps).setVisible(false);
if (slipAndDropIconOn)
menu.findItem(R.id.fall).setIcon(R.drawable.fall);
else
menu.findItem(R.id.fall).setVisible(false);
if (fesConnectIconOn)
menu.findItem(R.id.fesConnection).setIcon(R.drawable.fesconnect);
else
menu.findItem(R.id.fesConnection).setVisible(false);
}
public void changeMenuItem(int resId, int draId){
needToChangeMenuItem = true;
resourceId = resId;
drawableId = draId;
invalidateOptionsMenu();
}
MenuItem mi = (MenuItem) view.findViewById(R.id.opt_mnu_action);
mi.setIcon(R.drawable.ico_1);
In your Fragment's onCreateOptionsMenu, load this menu, and keep a reference to the menu item (it is not part of the fragment's view hierarchy so you can't use findViewById).
Whenerver you are ready to update the icon, use mi.setIcon(R.drawable.ico_1);
and call invalidateOptionsMenu().
UPDATED:
return super.onCreateOptionsMenu(menu);
This will actually return false, since the base implementation doesn't do that. Instead skip it, or just call super.onCreateOptionsMenu(menu); first, do your stuff and then return true.
First add actionOverFlowButtonStyle into your main theme
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:actionOverflowButtonStyle">#style/MyActionButtonOverflow</item>
</style>
Define the New style for action over flow button
<style name="MyActionButtonOverflow" parent="android:style/Widget.Holo.Light.ActionButton.Overflow">
<item name="android:src">#drawable/ic_menu</item>
</style>
I am trying to show/hide items in my action bar depending on which fragment is visible.
In my MainActivity I have the following
/* Called whenever invalidateOptionsMenu() is called */
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if(this.myFragment.isVisible()){
menu.findItem(R.id.action_read).setVisible(true);
}else{
menu.findItem(R.id.action_read).setVisible(false);
}
return super.onPrepareOptionsMenu(menu);
}
This works great however, when the device is rotated there is a issue. After the rotation is complete onPrepareOptionsMenu is called again however this time this.myFragment.isVisible() returns false...and hence the menu item is hidden when clearly the fragment is visible (as far as whats shown on the screen).
Based on the Fragments API Guide, we can add items to the action bar on a per-Fragment basis with the following steps:
Create a res/menu/fooFragmentMenu.xml that contains menu items as you normally would for the standard menu.
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/newAction"
android:orderInCategory="1"
android:showAsAction="always"
android:title="#string/newActionTitle"
android:icon="#drawable/newActionIcon"/>
</menu>
Toward the top of FooFragment's onCreate method, indicate that it has its own menu items to add.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
...
}
Override onCreateOptionsMenu, where you'll inflate the fragment's menu and attach it to your standard menu.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fooFragmentMenu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
Override onOptionItemSelected in your fragment, which only gets called when this same method of the host Activity/FragmentActivity sees that it doesn't have a case for the selection.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.newAction:
...
break;
}
return super.onOptionsItemSelected(item);
}
Try using Fragment's setRetainInstance(true); when your fragment is attached to the Activity. That way your fragment will retain it's current values and call the lifecycle when device rotated.
Edit: This is a quick and dirty fix, see es0329's answer below for a better solution.
Try adding this attribute to your activity tag in your android manifest:
android:configChanges="orientation|screenSize"
How to disable/hide three-dot indicator(Option menu indicator) on ICS handsets which does't have menu button. ?
I am running application as <uses-sdk android:minSdkVersion="5"/> in Manifest, code is compiled with 4.0. Three-dot indicator shows on every screen.
Example for preference activities i don't want show Three-dot indicator, since it does't have any menu options.
Adding android:targetSdkVersion="14" in manifest it works. However don't want hide/remove three dots button on all screens . Only in preference activities don't want to show this three dots button.
Override onPrepareOptionsMenu() in the fragment of the preference with this:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item= menu.findItem(R.id.menu_settings);
item.setVisible(false);
super.onPrepareOptionsMenu(menu);
return true;
}
if you have more then one item set all the items visibility flag to false
and add the command setHasOptionsMenu(true);
to the onCreate command
after you will set all the visibility of the items to false the menu will disappear
on activity, the only difference is the onPrepareOptionsMenu is boolean and you don't need to add the setHasOptionsMenu(true); command on the creation
I just deleted the method :
#Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
getSupportMenuInflater().inflate(R.menu.main, menu);
return true;
}
then that three-dot-menu goes away (:
Hope it helps.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return false;
}
There is no way to show/hide "three-dot" menu indicator for a single activity. You can hide this menu indicator only for entire app by specifying android:targetSdkVersion="14" (or above) in your manifest file.
However, this menu indicator is not showing on preferences activity if it extends from native android.preference.PreferenceActivity class. I have this scenario implemented in a few of my apps, and it works perfectly.
I assume you are using some custom preferences implementations which does not extends from PreferenceActivity. Android Dev Team suggests to always use PreferenceActivity for any preferences in your applications.
Way too late to the party here, I was trying to remove all my menu items and the 3-dots(option menu indicator), I did differently than the solution given here I am surprised that nobody had told it. There is a visibility tag that can be set to false and no changing of code in activity is required visibility=false does the trick
in res / menu /..
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
visibility=false
android:title="#string/action_settings"/>
override method and return false remember of not call super
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return false;
}
Remove this item in res / menu / main.xml
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="#string/action_settings"/>
In addition: do not add an item that has showAsAction="never"- this will avoid the dots from showing. If you have more items than can not be shown at once the dots will be there again (and they are items that are flagged ifRoom).
Following code worked for my app. Tried on Samsung Galaxy S4 (Android 4.3) and Nexus 4 (Android 4.2):
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item= menu.findItem(R.id.action_settings);
item.setVisible(false);
return true;
}
for hiding 3 dots in actionbar/ toolbar
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_dash_board_drawer, menu);
return false; //for visible 3 dots change to true, hiding false
}
You can actually change the Android targetVersion thus forcing the 3-dot menu to either hide or show. You need to override onCreate of your Activity like this :
#Override
public void onCreate(Bundle savedInstanceState) {
getApplicationInfo().targetSdkVersion = 10; // To enable the 3-dot menu call this code before super.OnCreate
super.onCreate(savedInstanceState);
}
#Override
public void onCreate(Bundle savedInstanceState) {
getApplicationInfo().targetSdkVersion = 14; // To disable the 3-dot menu call this code before super.OnCreate
super.onCreate(savedInstanceState);
}
Tested on Android 4.x.x and Android 3.0
I just excluded the "onCreateOptionsMenu"-method:
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
//Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_planos, menu);
return true;
}
If you simply want to hide the button, this solution is a bit of a hack but works across all versions of Android (using AppCompat) and doesn't affect your other menu items:
styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light">
...
<item name="android:actionOverflowButtonStyle">#style/AppTheme.Overflow</item>
<!-- If you're using AppCompat, instead use -->
<item name="actionOverflowButtonStyle">#style/AppTheme.Overflow</item>
</style>
<style name="AppTheme" />
<style name="AppTheme.Overflow">
<item name="android:src">#null</item>
</style>
If you want the Overflow button hidden only on some screens, you could make this an alternate theme (change AppTheme above to AppTheme.NoOverflow) that only certain activities use :
AndroidManifest.xml
<activity android:name=".NoOverflowActivity"
android:theme="#style/AppTheme.NoOverflow" >
This effectively just makes the icon have no width and height. I rarely recommend opposing design guidelines but in my scenario we used dedicated hardware that did not properly report a menu button was present.
Just want to improve #war_hero answer.
If You wanna set the visibility on run time You can use oncreateoptions menu parameter like this
Menu overflow;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.mymenu, menu);
this.overflow = menu;
return super.onCreateOptionsMenu(menu);
}
and then make a function to show or hide any menu item according to the index. for e.g.
public void hideorShowMenuItems(boolean bool){
overflow.getItem(1).setVisible(bool);
overflow.getItem(2).setVisible(bool);
overflow.getItem(3).setVisible(bool);
overflow.getItem(4).setVisible(bool);
overflow.getItem(5).setVisible(bool);
}
Copy paste this code in main.xml in menu folder
you just need to make the item android:visible="false"
<?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/action_settings"
android:orderInCategory="100"
android:visible="false"
android:title="#string/action_settings"
app:showAsAction="never" />
</menu>
Should be:
<item
android:id="#+id/linearlayout_splash"
android:orderInCategory="100"
android:showAsAction="never"
android:visible="false"
android:title="#string/action_settings"/>
If MainActivity is
public class MainActivity extends AppCompatActivity
In MainActivity Class, Remove the below code.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
Do it like this.
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// if nav drawer is opened, hide the action items
boolean drawerOpen = mDrawerLayout.isDrawerOpen(leftDrawer);
return (!drawerOpen);
}
I am checking if my navigation drawer is visible I will hide the menu and vice versa. You can use it according to you requirement. Hope this helps. Happy Coding. :)
This is how I find a solution of mine. It maybe helpful.
#Override
public boolean onKeyDown(int keycode, KeyEvent event ) {
//KEYCODE_MENU
if(keycode == KeyEvent.KEYCODE_MENU){
/* AlertDialog.Builder dialogBuilder
= new AlertDialog.Builder(this)
.setMessage("Test")
.setTitle("Menu dialog");
dialogBuilder.create().show();*/
return true;
// finish();
}
return super.onKeyDown(keycode,event);
}
I just used
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
Where R.menu.main is only an empty menu xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" ></menu>