DialogFragment OnCreateView与OnCreateDialog的自定义布局


80

我正在尝试使用自己的布局创建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. 所以在经过一段时间的搜索之后,我尝试了第二种方法,该方法涉及重写OnCreateView

因此,我注释掉了OnCreateDialog设置布局的两行,然后添加了以下内容:

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

我很沮丧


为时已晚,但仍张贴similiar:stackoverflow.com/questions/21258228/...
拉哈夫夏尔马

Answers:


36

第一种方法对我有用...直到我想使用FindViewByID。

我想您可能不了解findViewById()所返回的View 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

2
@gghuffer尽管已经晚了4个月,但我不认为此Exception是直接由上面的代码引起的。人们在添加内容后打电话requestFeature(...)(或类似的东西requestWindowFeature(Window.FEATURE_NO_TITLE);)(例如Exception消息已声明)是更常见的 。
Griddo

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之一。覆盖这两者将导致异常:“必须在添加内容之前调用requestFeature()”。

重要

要获取完整答案,请查看@TravisChristian注释。就像他说的那样,您确实可以覆盖这两者,但是当您已经创建对话框视图之后尝试对视图进行充气时,就会出现问题。


32
并非完全如此。您可以覆盖这两者(实际上DialogFragment就是这样),当您已经创建对话框视图之后尝试为视图充气时,就会出现问题。您仍然可以在onCreateView中执行其他操作,例如使用savedInstanceState,而不会引起异常。
特拉维斯·克里斯蒂安

3
同样在这里。需要同时支持。这就是将片段内联或用作对话框的想法。对我来说似乎是个虫子。我能做的最好的事情是设置对话框的标题,但是没有办法通过调用super并为返回的对话框对象设置标题来在onCreateDialog中添加取消按钮:final Dialog dialog = 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()调用中指定布局文件。
Zephyr

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
这个例子非常适合我。您必须将所有代码放入onCreateDialog中,而不是放在onCreateView中。此代码允许用户执行此操作以及获取按钮。完善!
布兰登

10

正如@Xavier Egea所说,如果同时实现了onCreateView()和onCreateDialog(),则冒着使“添加内容之前必须调用requestFeature()”崩溃的风险。这是因为当您将片段作为对话框显示(为什么)时,会同时调用onCreateDialog()和onCreateView()。正如Travis Christian提到的,在onCreateDialog()中创建对话框后,onCreateView()中的inflate()是导致崩溃的原因。

实现这两个功能的一种方法,但是避免了这种崩溃:使用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按钮呢?在OnCreateDialog中,我可以使用构建器来设置按钮,当对话框中的视图膨胀时,我应该在OnCreateView中做什么以获取按钮?
Varvara Kalinina '16

嗯,好像使用Builder给我例外。那么,如果视图在对话框中被放大,而当它只是一个片段时不设置任何按钮,那么设置按钮的方式将是什么呢?
Varvara Kalinina '16

好吧,事实证明,如果您调用dialog.setView而不是dialog.setContentView,即使您使用Builder创建对话框并设置按钮,此方法也能正常工作
Varvara Kalinina

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();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.