90 votes

Mise en page personnalisée pour DialogFragment OnCreateView vs. OnCreateDialog

J'essaie de créer un DialogFragment en utilisant ma propre mise en page.

J'ai vu plusieurs approches différentes. Parfois, la disposition est définie dans OnCreateDialog comme ceci : (J'utilise Mono mais je me suis un peu habitué à 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();
}

Cette première approche fonctionne pour moi... jusqu'à ce que je veuille utiliser findViewByID. Après quelques recherches sur Internet, j'ai donc essayé la deuxième approche qui consiste à remplacer OnCreateView

J'ai donc commenté deux lignes de OnCreateDialog qui a défini la mise en page et ensuite ajouté ceci :

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

ce qui me donne une belle erreur :

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

Je suis perplexe.

57voto

Freerider Points 1141

J'ai eu la même exception avec le code suivant :

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

Vous devez choisir de passer outre seulement un de onCreateView ou onCreateDialog dans un DialogFragment. Le fait de surcharger les deux donnera lieu à une exception : "requestFeature() doit être appelé avant l'ajout de contenu".

Important

Pour une réponse complète, consultez le commentaire de @TravisChristian. Comme il l'a dit, vous pouvez effectivement remplacer les deux, mais le problème vient lorsque vous essayez de gonfler la vue après avoir déjà créé la vue dialogue.

38voto

Sam Points 47925

Cette première approche fonctionne pour moi... jusqu'à ce que je veuille utiliser FindViewByID.

Je suppose que vous n'êtes pas en train d'évaluer findViewById() à la vue retournée par inflate() essayez ceci :

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

return b.create();

36voto

Zephyr Points 374

Le code ci-dessous provient du guide google, donc la réponse est que vous ne pouvez pas faire comme le vôtre dans onCreateDialog(), vous devez utiliser super.onCreateDialog() pour obtenir un dialogue.

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

18voto

I'm_With_Stupid Points 67

Voici un exemple d'utilisation de findViewById dans un fragment de dialogue

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

    }

11voto

Steve B Points 41

Comme le dit @Xavier Egea, si vous avez implémenté à la fois onCreateView() et onCreateDialog(), vous courez le risque d'obtenir le crash "requestFeature() must be called before adding content". C'est parce que les DEUX onCreateDialog() et onCreateView() sont appelés lorsque vous montrez() ce fragment comme un dialogue (pourquoi, je ne sais pas). Comme Travis Christian l'a mentionné, l'inflate() dans onCreateView() après qu'un dialogue ait été créé dans onCreateDialog() est ce qui cause le crash.

Une façon d'implémenter ces deux fonctions, mais d'éviter ce crash : utilisez getShowsDialog() pour limiter l'exécution de votre onCreateView() (afin que votre inflate() ne soit pas appelé). De cette façon, seul votre code onCreateDialog() est exécuté lorsque vous affichez votre DialogFragment sous forme de dialogue, mais votre code onCreateView() peut être appelé lorsque votre DialogFragment est utilisé comme fragment dans un layout.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X