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を再作成する方法はありますか?(私の場合、後者は少し高価なので)

編集:これは問題を示す最小限のサンプルプロジェクトです。

編集2:画面の幅を確認し、showAsActionフラグを常に適切に調整することを考えていましたが、各項目の幅を知る(または推測する)必要があります。ActionBarのパブリックAPIは、その点では役に立ちません。

4

3 に答える 3

6

私はこの問題に遭遇し、100% 機能するハックを思い付きました。

最後に、invalidateOptionsMenu() を 2 回呼び出しました。以下のコードを見てください。

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 に答える