Custom Layout for DialogFragment OnCreateView vs. OnCreateDialog
Solution 1
This first approach works for me... until I want to use FindViewByID.
I would guess that you are not scoping findViewById()
to the View returned by inflate()
, try this:
View view = i.inflate(Resource.Layout.frag_SelectCase, null);
// Now use view.findViewById() to do what you want
b.setView(view);
return b.create();
Solution 2
I had the same exception with the following 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;
}
}
You must choose to override only one of onCreateView or onCreateDialog in a DialogFragment. Overriding both will result in the exception: "requestFeature() must be called before adding content".
Important
For complete answer check the @TravisChristian comment. As he said, you can override both indeed, but the problem comes when you try to inflate the view after having already creating the dialog view.
Solution 3
Below code comes from google guide, so the answer is that you could not do like yours in onCreateDialog(), you must use super.onCreateDialog() to get a dialog.
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;
}
}
Solution 4
Here's an example of using findViewById in a Dialog Fragment
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();
}
Solution 5
As @Xavier Egea says, if you have both onCreateView() and onCreateDialog() implemented, you run the risk of getting the "requestFeature() must be called before adding content" crash. This is because BOTH onCreateDialog() then onCreateView() are called when you show() that fragment as a dialog (why, I don't know). As Travis Christian mentioned, the inflate() in onCreateView() after a dialog was created in onCreateDialog() is what causes the crash.
One way to implement both these functions, but avoid this crash: use getShowsDialog() to limit execution of your onCreateView() (so your inflate() is not called). This way only your onCreateDialog() code is executed when you are displaying your DialogFragment as a dialog, but your onCreateView() code can be called when your DialogFragment is being used as a fragment in a 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;
}
Comments
-
gghuffer almost 2 years
I'm trying to create a DialogFragment using my own Layout.
I've seen a couple different approaches. Sometimes the layout is set in OnCreateDialog like this: (I'm using Mono but I've gotten somewhat used to 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(); }
This first approach works for me... until I want to use
findViewByID.
so after a bit of googling I tried the second approach which involves overridingOnCreateView
So I commented out two lines of
OnCreateDialog
that set the Layout and then added this: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; }
which gives me a lovely error:
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
I'm stumped.
-
gghuffer over 11 yearsThis does indeed work. Thanks! I'm still curious as to why OnCreateView crashes though.
-
Gerrit-K about 11 years@gghuffer Although this is 4 months late, I don't think, that this Exception is directly caused by the code above. It's more common that people call
requestFeature(...)
(or something likerequestWindowFeature(Window.FEATURE_NO_TITLE);
) after adding content (like the Exception message already states). -
Travis Christian about 11 yearsThat's not entirely true. You can override both (in fact the DialogFragment says so), the problem comes when you try to inflate the view after having already creating the dialog view. You can still do other things in onCreateView, like use the savedInstanceState, without causing the exception.
-
farid_z almost 11 yearsSame here. Needs to support both. That's the idea of either using the fragment inline or as a dialog. Seems like a bug to me. The best I could do, is set the title for the dialog but no luck adding a cancel button in onCreateDialog by calling super and setting title to the returned dialog object: final Dialog dialog = super.onCreateDialog(savedInstanceState); dialog.setTitle(m_callback.getTitle()); // no luck adding cancel button return dialog;
-
Brandon about 9 yearsThis example works for me perfectly. You must put all your code into the onCreateDialog rather than from the onCreateView. This code allows the user to do just that as well as get the buttons. Perfect!
-
user1530779 over 8 yearsI don't see the point in doing this since onCreateView is configuring views anyways why do you wanna configure views at both places you can keep onCreateView as common inflating code and that will anyways be inflated in dialog
-
Varvara Kalinina over 7 years@user1530779 What about buttons? in OnCreateDialog i can use the builder to set the buttons and what am I supposed to do in OnCreateView to get the buttons when the view is inflated in dialog?
-
Varvara Kalinina over 7 yearsHmm, seems like using the Builder gives me exception. So what would be the way to setup buttons if the view is inflated in dialog and set no buttons when it's just a fragment?
-
Varvara Kalinina over 7 yearsWell, it turns out that if you call dialog.setView instead of dialog.setContentView this approach works fine even if you create your dialog with a Builder and set buttons
-
Daniel Gomez Rico over 6 yearsdo you have a link?
-
CopsOnRoad over 6 years@Zebphyr What if I want to use this CustomDialogFragment as a Dialog for my activity, but in the code above there is no mention of R.layout.my_layout in
onCreateDialog()
method. WillonCreateView()
will help in this case? -
Zephyr over 6 years@Jack Jan, Yes, you can specify the layout file in the onCreateView() call.