8

我有一个使用 ActionBar 的应用程序,我自己处理方向更改:

android:configChanges="keyboard|keyboardHidden|orientation|screenSize"

...并且菜单应该适合在 ActionBar 中而不会在横向溢出,但不是纵向:

<?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>

在启动时,这可以正常工作:

景观: 包含所有项目的宽 ActionBar

纵向:( 带有溢出的窄 ActionBar 是的,我可以强制所有项目始终显示并且它们适合,如下所示,但这可能会在较小的平板电脑上损坏)

当模拟器改变方向时,ActionBar 的容量似乎没有改变:

纵向,当我从横向开始时:( 包含所有项目的窄 ActionBar 这可以,但不一致)

风景,当我开始画肖像时: 带有溢出的宽 ActionBar 这看起来很傻,这就是我想要解决这个问题的原因。

我将此调用添加到invalidateOptionsMenu(),但它没有帮助:

@Override
public void onConfigurationChanged(Configuration newConfig)
{
    maybeMoveSomeViewsAround(newConfig);
    super.onConfigurationChanged(newConfig);
    invalidateOptionsMenu();
}

(实际上我通过反射调用它是为了向后兼容,但调试器告诉我它确实被调用并且没有遇到异常。)

invalidateOptionsMenu() 实际上最终会在返回之前调用 onCreateOptionsMenu() (它重新膨胀菜单),我可以在后者内部看到 getResources().getConfiguration().orientation 已经改变。所以这真的很令人费解。如果重新创建选项菜单,当方向改变时,一定是ActionBar本身缓存了宽度?

有没有办法在不破坏/创建 Activity 的情况下重新创建 ActionBar?(因为在我的情况下后者有点贵)

编辑:这是一个显示问题的最小示例项目。

编辑 2:我曾想过检查屏幕宽度并以编程方式在始终和从不之间适当地调整 showAsAction 标志,但这需要知道(或猜测)每个项目的宽度。ActionBar 的公共 API在这一点上对我没有帮助。

4

3 回答 3

6

我遇到了这个问题并想出了一个 100% 有效的 hack。

我两次调用 invalidateOptionsMenu() 。看下面的代码:

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();

}

并在你的 onCreateOptionsMenu() 中设置你想要显示的菜单项:

item.setShowAsAction(MenuItem.SHOW_AS_ACTION_WITH_TEXT | (hackActionBarReset ? MenuItem.SHOW_AS_ACTION_NEVER : MenuItem.SHOW_AS_ACTION_IF_ROOM));

不是一个漂亮的解决方案,但它有效。

于 2012-07-05T15:42:57.490 回答
2

我已经谨慎地解决了这个问题:当设备的宽度大于 850dip 时,强制显示 ActionBar 中的所有项目,否则继续让平台决定。

这是 git commit编辑:以及使用太新的字段修复的后续提交,哎呀。:-)

我肯定仍然对更好的答案感兴趣(除了等待修复平台)。

于 2011-10-02T21:57:08.050 回答
0

我发现最简单和最有效的解决方法是清除菜单然后重建它。

例如:

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.
    }
}
于 2013-01-08T12:26:52.097 回答