ActionBar容量/溢出在屏幕方向改变时没有改变

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本身缓存了宽度吗?

有没有一种方法可以重新创建ActionBar而不销毁/创建Activity? (因为在我的情况下后者有点昂贵)

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

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


你能否创建并发布一个完整的示例项目来演示这个问题?此外,您是否尝试在硬件上运行?这可能是模拟器特定的问题。 - CommonsWare
@CommonsWare 好的,看到我在结尾处的编辑了吗?这是一个示例项目。我目前没有平板电脑硬件,但我将于周三参加关于平板电脑的Android开发者实验室活动,所以我可以在那里尝试一下。 - Chris Boyle
1
我可以在运行Android 3.2的XOOM上重现这个问题。这感觉像是一个错误。我已经为此提交了一个问题:http://code.google.com/p/android/issues/detail?id=20493 - CommonsWare
3个回答

6

我也遇到了这个问题,并想出了一个100%有效的方法。

最终我调用了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));

这不是一个优美的解决方案,但它可以工作。


2
当设备的宽度大于850dip时,我已经小心地解决了这个问题:强制在ActionBar中显示所有项目,否则继续让平台决定。这是git提交的链接:这里。编辑:还有后续提交来修复使用太新的字段的问题。:-) 我肯定仍然对更好的答案感兴趣(除了等待平台修复)。

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.
    }
}

你不需要这样做。只需使用 invalidateOptionsMenu() - user924

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接