ActionBar capacity/overflow not changing on orientation change - android

I have an app using the ActionBar, where I handle orientation changes myself:
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
...and the menu should fit in the ActionBar without overflow in landscape, but not in portrait:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="#string/Game" android:id="#+id/game" android:icon="#android:drawable/ic_menu_manage" android:showAsAction="ifRoom|withText"/>
<item android:title="#string/Type" android:id="#+id/type" android:icon="#android:drawable/ic_menu_edit" android:showAsAction="ifRoom|withText"/>
<item android:title="#string/Other" android:id="#+id/other" android:icon="#android:drawable/ic_menu_gallery" android:showAsAction="ifRoom|withText"/>
<item android:title="#string/Solve" android:id="#+id/solve" android:icon="#android:drawable/ic_menu_directions" android:showAsAction="ifRoom|withText"/>
<item android:title="#string/Help" android:id="#+id/help" android:icon="#android:drawable/ic_menu_help" android:showAsAction="ifRoom"/>
</menu>
On startup, this works correctly:
Landscape:
Portrait:
(yes, I could force all items to always display and they would fit, as shown below, but that might break on a smaller tablet)
When the emulator changes orientation, the ActionBar's capacity doesn't seem to change:
Portrait, when I started in landscape:
(this is ok, but inconsistent)
Landscape, when I started in portrait:
This looks really silly and is the reason I want to fix this.
I added this call to invalidateOptionsMenu(), but it doesn't help:
#Override
public void onConfigurationChanged(Configuration newConfig)
{
maybeMoveSomeViewsAround(newConfig);
super.onConfigurationChanged(newConfig);
invalidateOptionsMenu();
}
(Actually I call it by reflection for backward compatibility, but the debugger tells me it really is called and does not encounter an exception.)
invalidateOptionsMenu() actually ends up calling onCreateOptionsMenu() (which re-inflates the menu) before returning, and I can see inside the latter that getResources().getConfiguration().orientation has already changed. So this is really puzzling. If the options menu is being recreated, when the orientation has changed, it must be ActionBar itself caching the width?
Is there a way to re-create the ActionBar without destroying/creating the Activity? (because the latter is a bit expensive in my case)
Edit: Here's a minimal sample project showing the issue.
Edit 2: I had thought of checking the screen width and programmatically adjusting the showAsAction flags between always and never appropriately, but that requires knowing (or guessing) the width of each item. ActionBar's public API does not help me on that point.

I ran into this problem to and came up with a hack which works 100%.
I eneded up calling invalidateOptionsMenu() two times. Look at the code below:
private boolean hackActionBarReset = false;
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//a hack to reset the items in the action bar.
hackActionBarReset = true;
invalidateOptionsMenu();
hackActionBarReset = false;
invalidateOptionsMenu();
}
And in your onCreateOptionsMenu() set this on you menuitems you want to show:
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_WITH_TEXT | (hackActionBarReset ? MenuItem.SHOW_AS_ACTION_NEVER : MenuItem.SHOW_AS_ACTION_IF_ROOM));
Not a pretty solution but it works.

I've cautiously worked around this: when the device's width is greater than 850dip, force showing all items in the ActionBar, otherwise continue to let the platform decide.
Here's the git commit. Edit: and the follow-up commit to fix using a field that's too new, oops. :-)
I'm definitely still interested in better answers (other than waiting for a fix to the platform).

I found that the simplest and most effective workaround was to clear the menu and then rebuild it.
For example:
Menu menu;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
this.menu = menu;
// Setup code goes here...
}
#Override
public void onOrientationChanged() {
if (menu != null) {
menu.close(); // Ensure the menu is closed before changing its contents.
menu.clear();
onCreateOptionsMenu(menu); // Rebuild the menu.
}
}

Related

the setting options in another activity

in my app on the top right of the action bar, I have the setting as three dots (as the usual setting). but when I click on it, it shows a white rectangle that has the word "setting" on it! But I don't want that!! I want just the three dots and when I click it I want it to take me to another activity right away(without showing the option setting on a rectangle).
this my code for the setting xml:
<item
android:id="#+id/action_settings"
android:orderInCategory="0"
android:title="#string/action_settings"
android:textColor="#color/colorBackground"
app:showAsAction="never" />
</menu>
The three dots you're talking about are usually there if you don't have enough room in your action bar and you want some of your menu items to show in a menu instead of directly displaying it to the action bar. The best thing for you is to create another item and set app:showAsAction to always and call a method using onOptionsItemSelected event:
<item
android:id="#+id/your_id"
android:title="your title"
app:showAsAction="always" />
Call it like this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.your_id:
//code here...
}
return super.onOptionsItemSelected(item);
}
Currently your app has a default menu that has a settings item added. You can create your own menu options.
Create a new menu.xml file that contains 1 item whose image is the three dots.
In your class, inside the onOptionsItemSelected method, call the activity that you want to open.
Hope this helps :)

How to parametrize options of a menu on Android?

I want to show/hide some options of a menu on an Android application depending of some strings that I will set to true/false on strings.xml file.
As an example, I will have these strings on strings.xml file:
<string name="option1">false</string>
<string name="option2">true</string>
<string name="option3">true</string>
So in this case only option2 and option3 have to be shown.
On the other side, I mean, in code, I tried the following:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
getMenuInflater().inflate(R.menu.main, menu);
if((getResources().getString(R.string.option1)).equals("false")){
menu.getItem(R.id.option1).setVisible(false);
}
return true;
}
But option1 is still being shown on the menu.
What should I do to parametrize these options? I could just remove these options but I would like that in the future if my clients want these options active again, I could do it easily changing false value to true.
EDIT: Here is my menu:
<?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/option1"
android:title="Option 1" />
<item
android:id="#+id/option2"
android:title="Option 2" />
<item
android:id="#+id/option3"
android:title="Option 3" />
....
</group>
</menu>
LAST UPDATE
I have notice that I was getting NullPointerException because the name of the menu was wrong. I have fixed it and now it does not give me any error.
But my problem comes because I have two different layouts that contains two different menus (one in each layout) and I inflate each layout depending of one string that comes on the login.
For example, considering that the string to inflate the first layout is "hello" I display the layouts as follows on onCreate function of my MainActivity:
if("hello".equals(stringForLayout)){
setContentView(R.layout.activity_main);
}else{
setContentView(R.layout.activity_main_secondary);
}
How can I parametrize the options of both menus so if the first one is being shown and I want to hide one option, I would be able to refer to that option of that menu?
Thanks in advance!
If you use Strings (e.g. s1 & s2), you have to compare them like this:
if(s1.equals(s2)) {...}
Btw.: You can also look at Shared Preferences in the android documentation to get a cleaner solution. There you can define boolean variables for the different menu options.
Finally, I found where my problems were.
The problem came because I did not notice that onCreateOptionsMenu and onPrepareOptionsMenu were not used so I deleted them.
Further, as I was using my menu inside a NavigationView I had to use, after inflate the NavigationView on my onCreate function of my MainActivity class, the following statement:
navigationView.getMenu().findItem(R.id.option1).setVisible(false);
There, I did not have any problem to hide my menu item succesfully.
Try this if you want to hide a specific menu item for a specific activity.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem mSearch = menu.findItem(R.id.mSearch);
mSearch.setVisible(false);
invalidateOptionsMenu();
}

Dynamic radio options in the Action Bar (Android)

I thought I should ask a new question for this, but for some context I was able to get the label in position thanks to the good people at How to get a label in the Android action bar
.
So now that I've got that, I want the user to be able to tap the Administrator button and then change it to a different mode (probably just "Administrator", "User", "Guest" to start with but there may be more in the future).
How can I get a list of radio boxes to appear when the button in the top right is clicked? Ideally I want to be able to define those various modes dynamically from within the Java class so that if a new type gets added to the database it will be automatically picked up.
If anyone could point me in the right direction I'd appreciate it. I have seen a few examples from Googling, but unfortunately none of them involved the sort of customised drawable I'm using - and none of them had dynamically populated radio options either.
Thanks
You probably want to have a menu which contains your different items.
Do something like this to create the menu and inflate your xml:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.my_menu, menu);
return true;
}
And then for handling the click events:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.admin:
switchToAdminUI();
return true;
case R.id.guest:
switchToGuestUI();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
And your my_menu.xml could look something like this:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/menu_overflow"
android:icon="#drawable/abs_ic_menu_moreoverflow_material"
android:showAsAction="always">
<menu>
<item
android:id="#+id/admin"
android:showAsAction="never"
android:icon="#drawable/ic_admin"
android:title="#string/admin"/>
<item
android:id="#+id/guest"
android:showAsAction="never"
android:icon="#drawable/ic_guest"
android:title="#string/guest"/>
</menu>
</item>
</menu>
You can see the android:showAsAction="always" above, which means that it will always show as an action bar icon, and then you put the sub menu items in there.
Try it out and you can also read more about menus here https://developer.android.com/guide/topics/ui/menus.html

showAsAction="ifRoom" doesn't show the item even when there is plenty of room

I am trying to get the ActionBar working properly on my app (and I'm using ActionBarSherlock to get a unified UI between Android 2.x and 4.x).
I feel like android:showAsAction="ifRoom" is just a big, fat lie. Whenever I set an action to ifRoom it ALWAYS shows up in the overflow menu even if there is PLENTY of room. Here are two screenshots from the same emulator. The first shows the ActionBar with all options set to always and the second shows the ActionBar with the last two options set to ifRoom. As you can see, there was PLENTY of room when they were all shown in the always screenshot, so why aren't they all showing in the second because they DO have room?
Here is my menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/add"
android:icon="#drawable/ic_menu_btn_add"
android:showAsAction="always"
android:title="Add"/>
<item
android:id="#+id/calculateNPV"
android:icon="#drawable/menu_icon_npv"
android:showAsAction="always"
android:title="NPV"/>
<item
android:id="#+id/calculateIRR"
android:icon="#drawable/menu_icon_irr"
android:showAsAction="always"
android:title="IRR/YR"/>
<item
android:id="#+id/send"
android:icon="#android:drawable/ic_menu_share"
android:showAsAction="always"
android:title="#string/share_pdf"/>
<item
android:id="#+id/graph"
android:icon="#drawable/ic_menu_gallery"
android:showAsAction="ifRoom"
android:title="#string/view_cashflow_diagram"/>
<item
android:id="#+id/deleteReorder"
android:icon="#drawable/ic_menu_clear_playlist"
android:showAsAction="ifRoom"
android:title="#string/delete_reorder_cashflows"/>
</menu>
It is really not a big fat lie but a small oversight.
The showAsAction attribute must be defined using a different namespace "http://schemas.android.com/apk/res-auto"
You should therefore in your top menu tag define a namespace as follows
xmlns:app="http://schemas.android.com/apk/res-auto"
and then use that to define your showAsAction attribute like so
app:showAsAction="ifRoom"
That should fix it
It's because there is specified maximum number of items that should go to actionbar and it seems to be 4. Of course you can force them to appear by setting showAsAction: always but regarding to google API guides:
If you believe that more than four of your menu items can be justified
as action items, then you should carefully consider their relative
level of importance and try to set no more than four as action items
(and do so using the "ifRoom" value to allow the system to put some
back in the overflow menu when space is limited on smaller screens).
Even if space is available on a wide screen, you should not create a
long stream of action items that clutter the UI and appear like a
desktop toolbar, so keep the number of action items to a minimum.
Additionally, the following actions should never appear as action
items: Settings, Help, Feedback, or similar. Always keep them in the
overflow menu.
To complement the answer from Michal Z.:
The Android Design Guide Page Patterns->Actionbar says the following in the chapter "Action Buttons":
http://developer.android.com/design/patterns/actionbar.html
How many actions will fit in the main action bar? Action bar capacity is controlled by the following rules:
Action buttons in the main action bar may not occupy more than 50% of the bar's width.
Action buttons on bottom action bars can use the entire width.
The screen width in density-independent pixels (dp) determine the number of items that will fit in the main action bar:
smaller than 360 dp = 2 icons
360-499 dp = 3 icons
500-599 dp = 4 icons
600 dp and larger = 5 icons
use app:showAsAction="always" instead of android:showAsAction="always"
Use
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
ActivityBar strives not to exceed some amount of visible elements. And that limit is lower than ActivityBar can contain indeed. The limit is set in android.support.v7.view.ActionBarPolicy class:
`/**
* Returns the maximum number of action buttons that should be permitted within an action
* bar/action mode. This will be used to determine how many showAsAction="ifRoom" items can fit.
* "always" items can override this.
*/
public int getMaxActionButtons() {
final Resources res = mContext.getResources();
final int widthDp = ConfigurationHelper.getScreenWidthDp(res);
final int heightDp = ConfigurationHelper.getScreenHeightDp(res);
final int smallest = ConfigurationHelper.getSmallestScreenWidthDp(res);
if (smallest > 600 || widthDp > 600 || (widthDp > 960 && heightDp > 720)
|| (widthDp > 720 && heightDp > 960)) {
// For values-w600dp, values-sw600dp and values-xlarge.
return 5;
} else if (widthDp >= 500 || (widthDp > 640 && heightDp > 480)
|| (widthDp > 480 && heightDp > 640)) {
// For values-w500dp and values-large.
return 4;
} else if (widthDp >= 360) {
// For values-w360dp.
return 3;
} else {
return 2;
}
}`
As you can see the limit is between 2 and 5, and it depends on the screen width.
I haven't been able to find a way to change this behavior. So if you want to exceed the limit, you should use showAsAction="always" or create your own view for ActionBar.
Use this below code it will always work
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<item
android:id="#+id/menu_share"
android:title="Share"
android:orderInCategory="100"
app:showAsAction="ifRoom"
android:actionProviderClass="android.widget.ShareActionProvider"/>
</menu>
Android will show at most 5 buttons, including the menu, indeed, but you can override that behavior if you want.
Keep in mind that the Material design guideline is to have a limited number of buttons on the toolbar. And keep in mind some actions should never be be displayed as buttons even if there's room.
But if you have a few specific actions that make sense, you can show them even if you will have more than 5 in total. You only have to check the screen width yourself.
First, in the menu definition, use "always" for up to 4 buttons you want to have displayed at all times. Use "never" for all the others, including those you may programmatically show as icons.
Then, override onPrepareOptionsMenu to add logic to force display a few more actions as buttons.
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
final Configuration config = getResources().getConfiguration();
final int width = config.screenWidthDp;
if (width > 400) {
MenuItem item = menu.findItem(R.id.your_action);
item.setShowAsAction(SHOW_AS_ACTION_ALWAYS);
item = menu.findItem(R.id.another_action);
item.setShowAsAction(SHOW_AS_ACTION_ALWAYS);
}
return super.onPrepareOptionsMenu(menu);
}
You can also do this dynamically, when the orientation changes, since there's usually enough room in landscape mode, especially on tablets.
#Override
public void onConfigurationChanged(#NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
invalidateOptionsMenu();
}
But don't clutter the toolbar. And remember to test this on small devices.
It has nothing to do with AppCompatActivity or appcompat library.
just use
menuInflater.inflate(R.menu.main_menu, menu)
instead of
MenuInflater(this).inflate(R.menu.main_menu, menu)

menu not visible on tablet

After hours of browsing the internet, I am still having a problem showing a menu on my app.
I have a viewflipper with in it several scrollviews and they have several layouts as well.
The whole app works great, I can swipe from scrollview to scrollview without any problems.
Before I connected a Samsung Galaxy Tab to play with, I was running the app in the emulator. There if I pressed the menu button, the submenu was showing and I was able to run functions on menu item touch.
On the tablet, the menu is not showing anywhere.
Here is my menu file:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/KPNsites"
android:icon="#drawable/ic_menu_name"
android:title="KPN Sites"/>
<item
android:id="#+id/VDFsites"
android:icon="#drawable/ic_menu_name"
android:title="Vodafone sites"/>
</menu>
In my activity I have this code:
#Override
public boolean onCreateOptionsMenu(Menu my_menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, my_menu);
return super.onCreateOptionsMenu(my_menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.KPNsites:
getKPNsiteInfo();
return true;
case R.id.VDFsites:
getVodafoneSiteInfo();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
When I run the app on the tablet, I only have a small bar at the top with only te app-name in it. I suspect the menu should be visible on that bar?
What else should I do / have done (differently)??
rg,
Eric
If your tablet is running Android 3.0 or greater you should change targetSdkVersion to <= 10 in manifest file.
You may want to consider using ActionBarSherlock this will give your app uniform and modern look on any Android version.
Try this example:
Menu Example
well gave it up for now.
every try messes up what I already got.
To get by, I've put buttons on the layout.
May be with the next project I get it working.
(but then by starting with it before I have all my layouts finished)
Thanks for the help!
rg,
Eric

Categories

Resources