开发者

ActionBar capacity/overflow not changing on orientation change

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:

ActionBar capacity/overflow not changing on orientation change

Portrait:

ActionBar capacity/overflow not changing on orientation change

(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:

ActionBar capacity/overflow not changing on orientation change

(this is ok, but inconsistent)

Landscape, when I started in portrait:

ActionBar capacity/overflow not changing on orientation change

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 gue开发者_如何学Pythonssing) 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.
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜