DialogFragmentOnCreateViewとOnCreateDialogのカスタムレイアウト


81

独自のレイアウトを使用してDialogFragmentを作成しようとしています。

私はいくつかの異なるアプローチを見てきました。レイアウトがOnCreateDialogで次のように設定されることがあります:(私はMonoを使用していますが、Javaにある程度慣れています)

public override Android.App.Dialog OnCreateDialog (Bundle savedInstanceState)
{
    base.OnCreateDialog(savedInstanceState);
    AlertDialog.Builder b = new AlertDialog.Builder(Activity);
        //blah blah blah
    LayoutInflater i = Activity.LayoutInflater;
    b.SetView(i.Inflate(Resource.Layout.frag_SelectCase, null));
    return b.Create();
}

この最初のアプローチは私にとってはうまくいきます...私が使いたいと思うまでfindViewByID. 、少しグーグルした後、私はオーバーライドを含む2番目のアプローチを試しましたOnCreateView

そこでOnCreateDialog、レイアウトを設定する2行をコメントアウトして、次のように追加しました。

public override Android.Views.View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    View v = inflater.Inflate(Resource.Layout.frag_SelectCase, container, false);
        //should be able to use FindViewByID here...
    return v;
}

それは私に素敵なエラーを与えます:

11-05 22:00:05.381: E/AndroidRuntime(342): FATAL EXCEPTION: main
11-05 22:00:05.381: E/AndroidRuntime(342): android.util.AndroidRuntimeException: requestFeature() must be called before adding content

私は困惑しています。


その遅すぎるが、それでも似投稿:stackoverflow.com/questions/21258228/...
ラガフシャルマ

回答:


37

この最初のアプローチは私にとってはうまくいきます... FindViewByIDを使いたいまで。

findViewById()によって返されたビューにスコープしていないと思います。inflate()これを試してください。

View view = i.inflate(Resource.Layout.frag_SelectCase, null);
// Now use view.findViewById() to do what you want
b.setView(view);

return b.create();

1
これは確かに機能します。ありがとう!OnCreateViewがクラッシュする理由についてはまだ興味があります。
gghuffer 2012年

2
@gghufferこれは4か月遅れていますが、この例外が上記のコードによって直接引き起こされているとは思いません。コンテンツを追加した後にrequestFeature(...)(またはそのようなものをrequestWindowFeature(Window.FEATURE_NO_TITLE);)呼び出すのが一般的です (例外メッセージがすでに述べているように)。
griddo 2013年

54

次のコードで同じ例外がありました。

public class SelectWeekDayFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
        .setMessage("Are you sure?").setPositiveButton("Ok", null)
        .setNegativeButton("No way", null).create();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.week_day_dialog, container, false);

        return view;    
    }
}

DialogFragmentのonCreateViewまたはonCreateDialogのいずれか1つのみをオーバーライドすることを選択する必要があります。両方をオーバーライドすると、「コンテンツを追加する前にrequestFeature()を呼び出す必要があります」という例外が発生します。

重要

完全な回答については、@ TravisChristianのコメントを確認してください。彼が言ったように、あなたは確かに両方をオーバーライドすることができます、しかし問題はあなたがすでにダイアログビューを作成した後にビューを膨らませようとすると起こります。


32
それは完全に真実ではありません。両方をオーバーライドできます(実際、DialogFragmentはそう言っています)。ダイアログビューを作成した後でビューを膨らませようとすると、問題が発生します。例外を発生させることなく、savedInstanceStateを使用するなど、onCreateViewで他のことを実行できます。
トラビスクリスチャン

3
こっちも一緒。両方をサポートする必要があります。これは、フラグメントをインラインで使用するか、ダイアログとして使用するという考え方です。私にはバグのようです。私ができる最善のことは、ダイアログのタイトルを設定することですが、superを呼び出して、返されたダイアログオブジェクトにタイトルを設定することにより、onCreateDialogにキャンセルボタンを追加することはできません。finalDialogdialog = super.onCreateDialog(savedInstanceState); dialog.setTitle(m_callback.getTitle()); //キャンセルボタンの戻りダイアログを追加しても運が悪い;
farid_z 2​​013年

33

以下のコードはグーグルガイドから来ているので、答えはあなたがonCreateDialog()であなたのようにすることができなかったということです、あなたはダイアログを得るためにsuper.onCreateDialog()を使わなければなりません。

public class CustomDialogFragment extends DialogFragment {
    /** The system calls this to get the DialogFragment's layout, regardless
        of whether it's being displayed as a dialog or an embedded fragment. */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Inflate the layout to use as dialog or embedded fragment
        return inflater.inflate(R.layout.purchase_items, container, false);
    }

    /** The system calls this only when creating the layout in a dialog. */
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // The only reason you might override this method when using onCreateView() is
        // to modify any dialog characteristics. For example, the dialog includes a
        // title by default, but your custom layout might not need it. So here you can
        // remove the dialog title, but you must call the superclass to get the Dialog.
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        return dialog;
    }
}

1
リンクはありますか?
ダニエルゴメスリコ

@ZebphyrこのCustomDialogFragmentをアクティビティのダイアログとして使用したいが、上記のコードではonCreateDialog()メソッドにR.layout.my_layoutについての言及がない場合はどうなりますか。ウィルonCreateView()この場合に役立つだろうか?
CopsOnRoad

@Jack Jan、はい、onCreateView()呼び出しでレイアウトファイルを指定できます。
ゼファー

16

ダイアログフラグメントでfindViewByIdを使用する例を次に示します。

public class NotesDialog extends DialogFragment {

        private ListView mNotes;
       private RelativeLayout addNote;

        public NotesDialog() {
            // Empty constructor required for DialogFragment
        }



        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {

            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

            View view = getActivity().getLayoutInflater().inflate(R.layout.note_dialog, null);
            mNotes = (ListView) view.findViewById(R.id.listViewNotes);
            addNote = (RelativeLayout) view.findViewById(R.id.notesAdd);

            addNote.setOnClickListener(new View.OnClickListener(){
                 @Override
                 public void onClick(View v){


                     getDialog().dismiss();

                     showNoteDialog();
                 }
             });

            builder.setView(view);

            builder.setTitle(bandString);


            builder.setNegativeButton("Cancel",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                          getDialog().dismiss();
                        }
                    }
                );


           return  builder.create();


    }

1
この例は私にとって完璧に機能します。すべてのコードをonCreateViewからではなくonCreateDialogに配置する必要があります。このコードを使用すると、ユーザーはボタンを取得するだけでなく、それを実行できます。完璧!
ブランドン

10

@Xavier Egeaが言うように、onCreateView()とonCreateDialog()の両方が実装されている場合、「コンテンツを追加する前にrequestFeature()を呼び出す必要があります」というクラッシュが発生するリスクがあります。これは、そのフラグメントをダイアログとして表示()すると、onCreateDialog()とonCreateView()の両方が呼び出されるためです(理由はわかりません)。Travis Christianが述べたように、ダイアログがonCreateDialog()で作成された後のonCreateView()のinflate()がクラッシュの原因です。

これらの両方の関数を実装する1つの方法ですが、このクラッシュを回避します。getShowsDialog()を使用して、onCreateView()の実行を制限します(したがって、inflate()は呼び出されません)。このように、DialogFragmentをダイアログとして表示しているときはonCreateDialog()コードのみが実行されますが、DialogFragmentがレイアウトのフラグメントとして使用されているときにonCreateView()コードを呼び出すことができます。

// Note: if already have onCreateDialog() and you only ever use this fragment as a 
// dialog, onCreateView() isn't necessary
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (getShowsDialog() == true) {  // **The key check**
        return super.onCreateView(inflater, container, savedInstanceState);
    } else {
        View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_alarm_dialog, null);    
        return configureDialogView(view);
    }
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{ 
    // Return custom dialog...
    Dialog dialog = super.onCreateDialog(savedInstanceState); // "new Dialog()" will cause crash

    View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_alarm_dialog, null);    
    configureDialogView(view);
    dialog.setContentView(view);

    return dialog;
}

// Code that can be reused in both onCreateDialog() and onCreateView()
private View configureDialogView(View v) {      
    TextView myText = (TextView)v.findViewById(R.id.myTextView);
    myText.setText("Some Text");

    // etc....

    return v;
}

onCreateViewはとにかく景色を構成しているので、私は、なぜあなたは、共通の膨張コードとしてonCreateView保つことができ、それはとにかく、ダイアログで膨張され、両方の場所でのビューを設定したくないこれを行うことでポイントが表示されない
user1530779

@ user1530779ボタンはどうですか?OnCreateDialogでは、ビルダーを使用してボタンを設定できます。ダイアログでビューが膨らんだときにボタンを取得するには、OnCreateViewで何をする必要がありますか?
Varvara Kalinina 2016年

うーん、ビルダーを使用すると例外が発生するようです。では、ダイアログでビューが膨らんでいて、フラグメントだけの場合はボタンを設定しない場合、ボタンを設定する方法は何でしょうか。
Varvara Kalinina 2016年

さて、dialog.setContentViewの代わりにdialog.setViewを呼び出すと、ビルダーでダイアログを作成してボタンを設定した場合でも、このアプローチは正常に機能することがわかります
Varvara

6

タイトルや閉じるボタンなどのダイアログプロパティに簡単にアクセスしたいが、独自のレイアウトも使用したい場合は、onCreateDialogをオーバーライドするときにBuilderでLayoutInflatorを使用できます。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = getActivity().getLayoutInflater();
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setMessage("Message!")
        .setTitle(this.dialogTitle)
        .setView(inflater.inflate(R.layout.numpad_dialog, null))
        .setPositiveButton(R.string.enter, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                // Clicked 'Okay'
            }
        })
        .setNegativeButton(R.string.dismiss, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                // Clicked 'Cancel'
            }
        });
    return builder.create();
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.