スポンサーリンク

2016年9月30日金曜日

Android AppCompatActivity で openOptionsMenu() が機能しない

AppCompatActivity を使っていて openOptionsMenu() が機能しないことに気づきました。普通の Activity であれば以下のコードでメオプションニューを起動できます。

    View button = findViewById(R.id.menu_button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            openOptionsMenu();
        }
    });

これが AppCompatActivity では機能しません。Google はどうもアクションバー以外からオプションメニューを起動させたくないようです。アクションバーを使用しない NoActionBar という選択肢もあるのに、それでも openOptionsMenu() は機能しません。

Activity や Fragment 上に配置したボタンからオプションメニューを起動したい場合もある筈です。なのでその方法を探してみました。
色々試してみました。結局メニューボタンをエミュレートする方法で何とかすることができました。他にも方法はあるかも知れません。

    View button = findViewById(R.id.menu_button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    // Menu ボタンのエミュレーション
                    Instrumentation instrumentation = new Instrumentation();
                    instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
                }
            };
            Thread thread = new Thread(runnable);
            thread.start();
        }
    });

Instrumentation クラスからキーコードを送信します。GUI をテストするユニットテストで使われているクラスです。この処理は UI スレッドで実行すると例外が発生するので、スレッドを起動します。

とにかくこれで一応オプションメニューを起動できるようになりました。アクションバーから起動したメニューは上から出てきますが、ボタンエミュレーションでは下から出てきます。

アクションバーで起動
ボタンエミュレーションで起動


しかし一つだけ問題があります。ボタンエミュレーションで起動したメニューにテーマが適用されないのです。上の例で見ても分かる通り、Light 系のテーマを使っているにも係わらず、ダーク系のメニューが表示されています。

これは原因を調べるのがちょっと厄介でした。結論から言うと、AppCompat 系の多くのテーマで actionBarPopupTheme が null に設定されているのが原因でした。これを適切に設定してやれば何とかなりそうです。例えば Light 系であれば以下のように、アプリケーションのテーマに一行追加します。

<style name="AppTheme" parent="Theme.AppCompat.Light">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>

    <item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>
</style>

ダーク系であれば以下の一行を追加します。

    <item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat</item>

これでボタンエミュレーションからのメニューでもテーマに沿った色になりました。




0 件のコメント :

コメントを投稿