2013/11/24

Dialog Theme を適用した Activity に ActionBar を表示する

Android でダイアログを表示する際、DialogFragment を使用するのではなく、Activity に Dialog Theme を適用して表示することが出来ます。
何かのリザルトを表示する時等、使い方によっては大変便利です。

ところで、せっかく Activity を使っているのだから、メニューを表示したいと思うのは私だけでしょうか?
Android 2.x 系だとメニューボタンを押したら、下からニュッとメニューが表示されるので、Dialog Theme を適用した Activity でもメニューを使用する事が出来ます。
しかし、Android 3.x から導入されたメニューは ActionBar。 Dialog Theme を適用すると表示されなくなってしまいます。

とはいえ、物は Activity なので、以下のように Custom Theme を作成することで、Action Bar を復活させることが可能です。

Dialog Theme を作る

Dialog の見た目を持つ Theme を作ります。
一から作成しても良いのですが、継承を使うと楽に作れます。

res/values-v11/theme.xml
<resources>

    <style name="AppTheme" parent="@android:Theme.Holo.Light" />
    <style name="Theme.MyTheme.Dialog.ActionBar" parent="@android:style/Theme.Holo.Light.Dialog">
        <!-- ActionBar を表示する -->
        <item name="android:windowActionBar">true</item>

        <!-- これがないとエラー -->
        <item name="android:windowIsFloating">false</item>

        <!-- これがないとDialog風にならない -->
        <item name="android:windowIsTranslucent">true</item>
    </style>

</resources>

今回は v11 (Android 3.0) 以降がターゲットなのですが、デフォルトにも同じ名前の Theme がないとエラーになってしまいますので、 以下のように追加します。

res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="AppTheme" parent="@android:style/Theme.Black" />
    <style name="Theme.MyTheme.Dialog.ActionBar" parent="@android:style/Theme.Dialog" />

</resources>

Activity に Dialog Theme を適用する

AndroidManifest に Activity を追加し、以下のように先ほど作った Theme を適用すれば Action Bar を持った Dialog の完成です。

AndroidManifest.xml
<activity
    android:theme="@style/Theme.MyTheme.Dialog.ActionBar"
    android:name="com.example.actionbar.DialogActivity"
    android:label="@string/title_activity_dialog" >
</activity>

補足

このダイアログは 見た目は Dialog ですが、Activity です。
Activity は Task 管理されているということを意識しておかないと問題になる場合があるでしょう。

DialogFragment 等は Activity に紐づいているので、必ず特定の Activity の上に表示されます。
しかし、今回の Activity は独立していますので、その順番が保障されていません。
外部からの Intent で別の Activity が起動したりするようなアプリだと、予期せぬ Activity の上に Dialog が表示されしまうケースが出てくるかもしれません。

落穂ひろい

android:windowActionBar を適用して、android:windowIsFloating を false にしないと、以下のようなエラーが出てしまいます。

FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.actionbar/com.example.actionbar.DialogActivity}: java.lang.IllegalStateException: ActionBarImpl can only be used with a compatible window decor layout
 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
 at android.app.ActivityThread.access$600(ActivityThread.java:141)
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
 at android.os.Handler.dispatchMessage(Handler.java:99)
 at android.os.Looper.loop(Looper.java:137)
 at android.app.ActivityThread.main(ActivityThread.java:5103)
 at java.lang.reflect.Method.invokeNative(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:525)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
 at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: ActionBarImpl can only be used with a compatible window decor layout
 at com.android.internal.app.ActionBarImpl.init(ActionBarImpl.java:188)
 at com.android.internal.app.ActionBarImpl.(ActionBarImpl.java:156)
 at android.app.Activity.initActionBar(Activity.java:1881)
 at android.app.Activity.setContentView(Activity.java:1896)
 at com.example.actionbar.DialogActivity.onCreate(DialogActivity.java:13)
 at android.app.Activity.performCreate(Activity.java:5133)
 at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
k ... 11 more

0 件のコメント: