web-dev-qa-db-ja.com

DialogFragmentのActionBar

Galaxy Tab 10.1のカレンダーアプリで新しいイベントを作成すると、ダイアログのタイトルバー/アクションバー領域に[完了]ボタンと[キャンセル]ボタンが表示されます。

enter image description here

これをアプリに実装したいと思います。 onCreateOptionsMenuサブクラスでDialogFragmentをオーバーライドすることに加えてsetHasOptionsMenu(true)を使用しようとしましたが、アクション項目が表示されません。 onCreateView内からgetDialog().getActionBar()を呼び出してみましたが、常にnullを返します。

ダイアログを表示するのではなくActivityを開始すれば、これを機能させることができますが、それは画面全体を占有します。 DialogFragmentを使用してこれを行う標準的な方法はありますか?

46
Paul Blessing

google group post のアイデアを使用して、アクティビティのスタイリングからそれを引き出すことができました。できれば高さと幅を「動的な」サイズに変更してください。次に、必要なActionBarボタンを設定します

<style name="PopupTheme" parent="Android:Theme.Holo.Light.Dialog">
    <item name="Android:windowIsFloating">false</item>
    <item name="Android:windowContentOverlay">@null</item>
    <item name="Android:windowSoftInputMode">stateAlwaysHidden</item>
    <item name="Android:windowActionModeOverlay">true</item>
    <item name="Android:windowIsTranslucent">true</item>
</style>

-

public static void showAsPopup(Activity activity) {
    //To show activity as dialog and dim the background, you need to declare Android:theme="@style/PopupTheme" on for the chosen activity on the manifest
    activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    LayoutParams params = activity.getWindow().getAttributes(); 
    params.height = 850; //fixed height
    params.width = 850; //fixed width
    params.alpha = 1.0f;
    params.dimAmount = 0.5f;
    activity.getWindow().setAttributes((Android.view.WindowManager.LayoutParams) params); 
    setContentView(R.layout.activity_main);
}
86
StrikeForceZero

ActionBarSherlockを使用している場合は、テーマを次のように宣言します。

<style name="PopupTheme" parent="Theme.Sherlock">
    <item name="Android:windowFrame">@null</item>
    <item name="Android:windowIsFloating">false</item>
    <item name="Android:windowContentOverlay">@null</item>
    <item name="Android:windowAnimationStyle">@Android:style/Animation.Dialog</item>
    <item name="Android:windowSoftInputMode">stateAlwaysHidden</item>
    <item name="Android:windowActionModeOverlay">true</item>
    <item name="Android:colorBackgroundCacheHint">@null</item>
    <item name="Android:windowCloseOnTouchOutside">true</item>
    <item name="Android:windowIsTranslucent">true</item>
    <item name="windowContentOverlay">@null</item>
</style>

そして、 Luke Sleeman's answer に従ってPopupThemeでSherlockActivityを初期化します。

private void showAsPopup(SherlockActivity activity) {
    //To show activity as dialog and dim the background, you need to declare Android:theme="@style/PopupTheme" on for the chosen activity on the manifest
    //activity.requestWindowFeature(Window.FEATURE_ACTION_BAR); // NO NEED to call this line.
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    LayoutParams params = activity.getWindow().getAttributes(); 
    params.alpha = 1.0f;
    params.dimAmount = 0.5f;
    activity.getWindow().setAttributes((Android.view.WindowManager.LayoutParams) params); 

    // This sets the window size, while working around the IllegalStateException thrown by ActionBarView
    activity.getWindow().setLayout(width,height);
}

結果:

enter image description here

14
nagoya0

StrikeForceZeroとLuke Sleemanから提案されたソリューションを実装するのに苦労したので、私は自分の経験を貢献したいと思いました。不足しているものがあるので、フィードバックをいただければ幸いです。

私がしたことは次のとおりでした:

  1. 提供されたPopupThemeを使用してスタイルを作成し、そのままコピー/貼り付けます:

    <style name="PopupTheme" parent="Android:Theme.Holo.Light.Dialog">
        <item name="Android:windowIsFloating">false</item>
        <item name="Android:windowContentOverlay">@null</item>
        <item name="Android:windowSoftInputMode">stateAlwaysHidden</item>
        <item name="Android:windowActionModeOverlay">true</item>
        <item name="Android:windowIsTranslucent">true</item>
    </style>
    
  2. ShowAsPopup()メソッドを、偽のダイアログフラグメントを開くフラグメント内のメソッドとして、直接コピー/貼り付けを追加します。

    private void showAsPopup(Activity activity) {
        //To show activity as dialog and dim the background, you need to declare Android:theme="@style/PopupTheme" on for the chosen activity on the manifest
        activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
        activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        LayoutParams params = activity.getWindow().getAttributes(); 
        params.alpha = 1.0f;
        params.dimAmount = 0f;
        activity.getWindow().setAttributes((Android.view.WindowManager.LayoutParams) params); 
    
        // This sets the window size, while working around the IllegalStateException thrown by ActionBarView
        activity.getWindow().setLayout(850,850);
    }
    
  3. 単純なnew()呼び出しを使用して新しいアクティビティのインスタンスを作成し、それをshowAsPopup()メソッドに渡します。

    DialogTestActivity test = new DialogTestActivity();
    showAsPopup(test);
    
  4. テストの目的で(アクションバーとダイアログとして表示されるアクティビティを開くことができることを確認しようとしていた)ボタンビューAPIデモから直接盗まれた非常に簡単なテストを使用しました(レイアウトファイル用) 、APIデモのbuttons_1.xmlを参照してください):

    public class DialogTestActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.buttons_test);
        }
    }
    

残念ながら、これを試みるたびに、最初の呼び出しactivity.requestWindowFeature(Window.FEATURE_ACTION_BAR);で不特定のNULLポインター例外が発生します。

04-29 16:39:05.361: W/System.err(15134): Java.lang.NullPointerException
04-29 16:39:05.361: W/System.err(15134):    at Android.app.Activity.requestWindowFeature(Activity.Java:3244)
04-29 16:39:05.371: W/System.err(15134):    at packagenameremovedforlegalreasons.classname.showAsPopup(classname.Java:602)
04-29 16:39:05.371: W/System.err(15134):    at packagenameremovedforlegalreasons.classname.onMapLongClick(classname.Java:595)
04-29 16:39:05.371: W/System.err(15134):    at com.google.Android.gms.maps.GoogleMap$5.onMapLongClick(Unknown Source)
04-29 16:39:05.371: W/System.err(15134):    at com.google.Android.gms.internal.k$a.onTransact(Unknown Source)
04-29 16:39:05.381: W/System.err(15134):    at Android.os.Binder.transact(Binder.Java:310)
04-29 16:39:05.381: W/System.err(15134):    at com.google.Android.gms.maps.internal.IOnMapLongClickListener$Stub$Proxy.onMapLongClick(IOnMapLongClickListener.Java:93)
04-29 16:39:05.381: W/System.err(15134):    at maps.i.s.a(Unknown Source)
04-29 16:39:05.381: W/System.err(15134):    at maps.y.v.d(Unknown Source)
04-29 16:39:05.381: W/System.err(15134):    at maps.y.bf.onLongPress(Unknown Source)
04-29 16:39:05.381: W/System.err(15134):    at maps.d.v.onLongPress(Unknown Source)
04-29 16:39:05.381: W/System.err(15134):    at maps.d.h.c(Unknown Source)
04-29 16:39:05.381: W/System.err(15134):    at maps.d.h.c(Unknown Source)
04-29 16:39:05.381: W/System.err(15134):    at maps.d.j.handleMessage(Unknown Source)
04-29 16:39:05.391: W/System.err(15134):    at Android.os.Handler.dispatchMessage(Handler.Java:99)
04-29 16:39:05.391: W/System.err(15134):    at Android.os.Looper.loop(Looper.Java:137)
04-29 16:39:05.391: W/System.err(15134):    at Android.app.ActivityThread.main(ActivityThread.Java:5041)
04-29 16:39:05.391: W/System.err(15134):    at Java.lang.reflect.Method.invokeNative(Native Method)
04-29 16:39:05.391: W/System.err(15134):    at Java.lang.reflect.Method.invoke(Method.Java:511)
04-29 16:39:05.391: W/System.err(15134):    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:793)
04-29 16:39:05.391: W/System.err(15134):    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:560)
04-29 16:39:05.391: W/System.err(15134):    at dalvik.system.NativeStart.main(Native Method)

スタックトレースからわかるように、意図された動作は、GoogleMapインスタンスを長押ししてウィンドウを開くことです(API 2のMapFragmentsを使用)。そのため、最初に考えたのは、フラグメントから開こうとすると問題が発生したため、所有しているアクティビティにコールバックを渡しました。同じエラー、同じ追加情報なし。

この時点での最良の推測は、new()呼び出しがビューを変更するための呼び出しを行うためにクラス/ビューを十分にインスタンス化していないことでした。ビュー変更コードをアクティビティに移行し、通常の方法でアクティビティを開くだけで機能するため、これは少なくともある程度正しいように見えます:

呼び出しアクティビティ:

    public void openMapDialog()
    {
        Intent intent = new Intent(this, DialogTestActivity.class);
        startActivity(intent);
    }

新しいクラスコード:

    public class DialogTestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // From: https://stackoverflow.com/questions/11425020/actionbar-in-a-dialogfragment
        this.requestWindowFeature(Window.FEATURE_ACTION_BAR);
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        LayoutParams params = this.getWindow().getAttributes(); 
        params.alpha = 1.0f;
        params.dimAmount = 0f;
        this.getWindow().setAttributes((Android.view.WindowManager.LayoutParams) params); 

        // This sets the window size, while working around the IllegalStateException thrown by ActionBarView
        this.getWindow().setLayout(600,600);

        setContentView(R.layout.buttons_test);
        }
    }

したがって、これらすべてを投稿することのポイントは、上記のポスターが示唆していることをしたい場合、アクティビティを単にnew()してshowAsPopup()を呼び出すことはできないことを明確にすることだと思います。これはAndroidが透けて見えますが、これは少し明白なように見えますが、showAsPopup()は作成中のビューではなく現在のビューによって呼び出されていると解釈するのも自然ですアクティビティインスタンスを渡すので(これがonCreate()で行われることになっていた場合はthisになります)。

したがって、createdアクティビティではなく、creatingアクティビティでshowAsPopup()を呼び出すことが意図されている場合、取得方法は明らかではありませんonCreate()が呼び出される前に変更可能なActivityインスタンス。問題は、setContentView()が呼び出された後にrequestWindowFeature()などを呼び出せないことです( example )。これは、通常onCreate()で呼び出されるため、問題です。

繰り返しますが、これを行うための簡単/より良い方法があれば、フィードバックに感謝します。うまくいけば、これがこのアプローチを使用したい人々に役立つことを願っています。

11
user1475907

私はこれで遊んで信じられないほどの時間を費やしました。受け入れられた回答はgalaxy nexus 7(Android 4.2)で機能しますが、samsung galaxy SIII(Android 4.1)およびsamsung galaxy tab 10.2(Android 4.0)では失敗しますが、次の例外があります。

IllegalStateException: ActionBarView can only be used with Android:layout_width="match_parent" (or fill_parent)

これは、レイアウトがmatch_parentに設定されていることを確認する ActionBarView.onMeasure(int、int) のコードが原因です。正しい解決策は、代わりにsetAttributesを使用する代わりにsetLayoutを介してウィンドウの幅を設定することです。

これはshowAsPopup()の修正バージョンであり、私がテストしたすべてのデバイスで機能します。

private void showAsPopup(Activity activity) {
    //To show activity as dialog and dim the background, you need to declare Android:theme="@style/PopupTheme" on for the chosen activity on the manifest
    activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
    activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    LayoutParams params = activity.getWindow().getAttributes(); 
    params.alpha = 1.0f;
    params.dimAmount = 0f;
    activity.getWindow().setAttributes((Android.view.WindowManager.LayoutParams) params); 

    // This sets the window size, while working around the IllegalStateException thrown by ActionBarView
    activity.getWindow().setLayout(850,850);
}

完全を期すために、ここに再びPopupThemeがあります。

<style name="PopupTheme" parent="Android:Theme.Holo.Light.Dialog">
    <item name="Android:windowIsFloating">false</item>
    <item name="Android:windowContentOverlay">@null</item>
    <item name="Android:windowSoftInputMode">stateAlwaysHidden</item>
    <item name="Android:windowActionModeOverlay">true</item>
    <item name="Android:windowIsTranslucent">true</item>
</style>
4
Luke Sleeman

私はおそらくそれほど経験はありませんが、アクティビティを使用し、アクションバーの項目を追加してから:

<activity Android:name=".YourActivity"Android:theme="@Android:style/Theme.Holo.Light.Dialog" />

お役に立てば幸いです!

1
Maxwell Weru

Veetiが暗示しているように、Dialogテーマでアクティビティを実装してみてください。 Android Manifest:

<activity Android:name=".YourActivity" Android:theme="@Android:style/Theme.Dialog </activity>

うまくいけばそれが助けになるでしょう。

1

DialogFragmentのalertDialogのビルダーで setCustomTitle を使用して、それを行う素敵な方法を見つけました(alertDialog自体でも可能です)。

public Dialog onCreateDialog(final Bundle savedInstanceState) {
    final AlertDialog.Builder builder = new AlertDialog.Builder(activity,...);
    final Toolbar toolbar = (Toolbar) inflater.inflate(R.layout.dialog_app_filter_toolbar, null, false);
    // <= prepare toolbar and dialog here
    return builder.create();
    }

そして結果( my app から):

enter image description here

enter image description here

AlertDialogを使用したくない場合でも、ダイアログのレイアウトにツールバーを配置して使用することができます。

1

私はそれが本当の答えではないことを知っていますが、上記の解決策は非常に洗練されていないため、.noActionBarを使用して何かからダイアログテーマを継承し、パネルの上部にビューを作成するなど、アクションバーをまったく避ける方が簡単だと思うかもしれませんこれはアクションバーを模倣し、少なくともこの方法ではすべてxlmに残ります。

0
mariubog