Benutzerdefiniertes Layout für DialogFragment OnCreateView vs. OnCreateDialog

79

Ich versuche, ein DialogFragment mit meinem eigenen Layout zu erstellen.

Ich habe ein paar verschiedene Ansätze gesehen. Manchmal wird das Layout in OnCreateDialog folgendermaßen festgelegt: (Ich verwende Mono, habe mich aber etwas an Java gewöhnt.)

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();
}

Dieser erste Ansatz funktioniert für mich ... bis ich ihn verwenden möchte. findViewByID. Nach einigem googeln habe ich den zweiten Ansatz ausprobiert, bei dem es um das Überschreiben gehtOnCreateView

Also habe ich zwei Zeilen OnCreateDialogauskommentiert, die das Layout festlegen, und dann Folgendes hinzugefügt:

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;
}

was mir einen schönen Fehler gibt:

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

Ich bin ratlos.

gghuffer
quelle
Es ist zu spät, aber es wird immer noch das Gleiche gepostet
Raghav Sharma

Antworten:

36

Dieser erste Ansatz funktioniert für mich ... bis ich FindViewByID verwenden möchte.

Ich würde vermuten, dass Sie nicht findViewById()auf die von zurückgegebene Ansicht zugreifen. inflate()Versuchen Sie Folgendes :

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

return b.create();
Sam
quelle
1
Das funktioniert tatsächlich. Vielen Dank! Ich bin immer noch gespannt, warum OnCreateView abstürzt.
Gghuffer
2
@gghuffer Obwohl dies 4 Monate zu spät ist, glaube ich nicht, dass diese Ausnahme direkt durch den obigen Code verursacht wird. Es ist üblicher, dass Benutzer nach dem Hinzufügen von Inhalten anrufen requestFeature(...)(oder so ähnlich requestWindowFeature(Window.FEATURE_NO_TITLE);) (wie in der Ausnahmemeldung bereits angegeben).
Griddo
53

Ich hatte die gleiche Ausnahme mit dem folgenden Code:

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;    
    }
}

Sie müssen festlegen , dass nur eines von onCreateView oder onCreateDialog in einem DialogFragment überschrieben wird. Das Überschreiben beider führt zur Ausnahme: "requestFeature () muss vor dem Hinzufügen von Inhalten aufgerufen werden".

Wichtig

Eine vollständige Antwort finden Sie im Kommentar @TravisChristian. Wie er sagte, können Sie beide zwar überschreiben, aber das Problem tritt auf, wenn Sie versuchen, die Ansicht aufzublasen, nachdem Sie die Dialogansicht bereits erstellt haben.

Xavier Egea
quelle
32
Das stimmt nicht ganz. Sie können beide überschreiben (tatsächlich sagt das DialogFragment dies). Das Problem tritt auf, wenn Sie versuchen, die Ansicht aufzublasen, nachdem Sie die Dialogansicht bereits erstellt haben. Sie können in onCreateView noch andere Dinge tun, z. B. den savedInstanceState verwenden, ohne die Ausnahme zu verursachen.
Travis Christian
3
Hier gilt das gleiche. Muss beide unterstützen. Das ist die Idee, das Fragment entweder inline oder als Dialog zu verwenden. Scheint mir ein Fehler zu sein. Das Beste, was ich tun kann, ist, den Titel für den Dialog festzulegen, aber kein Glück, eine Abbruchschaltfläche in onCreateDialog hinzuzufügen, indem ich super aufrufe und den Titel für das zurückgegebene Dialogobjekt festlege: final Dialog dialog = super.onCreateDialog (savedInstanceState); dialog.setTitle (m_callback.getTitle ()); // kein Glück beim Hinzufügen der Schaltfläche zum Abbrechen der Schaltfläche "Zurück";
farid_z
33

Der folgende Code stammt aus dem Google-Handbuch. Die Antwort lautet also, dass Sie Ihren in onCreateDialog () nicht mögen könnten. Sie müssen super.onCreateDialog () verwenden, um einen Dialog zu erhalten.

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;
    }
}
Zephyr
quelle
1
Hast du einen Link?
Daniel Gomez Rico
@Zebphyr Was ist, wenn ich dieses CustomDialogFragment als Dialog für meine Aktivität verwenden möchte, aber im obigen Code wird R.layout.my_layout in der onCreateDialog()Methode nicht erwähnt . Wird onCreateView()in diesem Fall helfen?
CopsOnRoad
@ Jack Jan, Ja, Sie können die Layoutdatei im Aufruf von onCreateView () angeben.
Zephyr
16

Hier ist ein Beispiel für die Verwendung von findViewById in einem Dialogfragment

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();


    }
Ich bin mit dumm
quelle
1
Dieses Beispiel funktioniert bei mir perfekt. Sie müssen Ihren gesamten Code in den onCreateDialog und nicht in den onCreateView einfügen. Mit diesem Code kann der Benutzer genau das tun und die Schaltflächen abrufen. Perfekt!
Brandon
10

Wie @Xavier Egea sagt, besteht bei der Implementierung von onCreateView () und onCreateDialog () die Gefahr, dass der Absturz "requestFeature () muss vor dem Hinzufügen von Inhalten aufgerufen werden" auftritt. Dies liegt daran, dass sowohl onCreateDialog () als auch onCreateView () aufgerufen werden, wenn Sie dieses Fragment als Dialog anzeigen () (warum, ich weiß nicht). Wie Travis Christian erwähnt hat, verursacht das Aufblasen () in onCreateView (), nachdem ein Dialog in onCreateDialog () erstellt wurde, den Absturz.

Eine Möglichkeit, diese beiden Funktionen zu implementieren, aber diesen Absturz zu vermeiden: Verwenden Sie getShowsDialog (), um die Ausführung von onCreateView () einzuschränken (sodass inflate () nicht aufgerufen wird). Auf diese Weise wird nur Ihr onCreateDialog () - Code ausgeführt, wenn Sie Ihr DialogFragment als Dialog anzeigen. Ihr onCreateView () - Code kann jedoch aufgerufen werden, wenn Ihr DialogFragment als Fragment in einem Layout verwendet wird.

// 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;
}
Steve B.
quelle
Ich sehe keinen Sinn darin, da onCreateView sowieso Ansichten konfiguriert. Warum möchten Sie Ansichten an beiden Stellen konfigurieren? Sie können onCreateView als allgemeinen Aufblascode beibehalten und dieser wird sowieso im Dialog aufgeblasen
user1530779
@ user1530779 Was ist mit Schaltflächen? In OnCreateDialog kann ich den Builder verwenden, um die Schaltflächen festzulegen. Was soll ich in OnCreateView tun, um die Schaltflächen abzurufen, wenn die Ansicht im Dialogfeld aufgeblasen wird?
Varvara Kalinina
Hmm, anscheinend gibt mir die Verwendung des Builders eine Ausnahme. Wie können Sie also Schaltflächen einrichten, wenn die Ansicht im Dialogfeld aufgeblasen ist, und keine Schaltflächen festlegen, wenn es sich nur um ein Fragment handelt?
Varvara Kalinina
Nun, es stellt sich heraus, dass, wenn Sie dialog.setView anstelle von dialog.setContentView aufrufen, dieser Ansatz auch dann gut funktioniert, wenn Sie Ihren Dialog mit einem Builder erstellen und Schaltflächen festlegen
Varvara Kalinina
6

Wenn Sie einfachen Zugriff auf die Dialogfeldeigenschaften wie den Titel und die Schaltfläche zum Schließen haben möchten, aber auch Ihr eigenes Layout verwenden möchten, können Sie mit Ihrem Builder einen LayoutInflator verwenden, wenn Sie onCreateDialog überschreiben.

@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();
}
Jason Hartley
quelle