DialogFragment OnCreateView与OnCreateDialog的自定义布局

ggh*_*fer 74 java mono android xamarin.android android-inflate

我正在尝试使用自己的布局创建一个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();
}
Run Code Online (Sandbox Code Playgroud)

第一种方法对我有用......直到我想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;
}
Run Code Online (Sandbox Code Playgroud)

这给了我一个可爱的错误:

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
Run Code Online (Sandbox Code Playgroud)

我很难过.

Xav*_*gea 53

我有以下代码的相同异常:

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;    
    }
}
Run Code Online (Sandbox Code Playgroud)

您必须选择覆盖DialogFragment中的onCreateView或onCreateDialog中的一个.覆盖两者将导致异常:"在添加内容之前必须调用requestFeature()".

重要

如需完整答案,请查看@TravisChristian评论.正如他所说的,你可以确实覆盖它们,但是当你在创建对话框视图后尝试给视图充气时会出现问题.

  • 这不完全正确.你可以覆盖它们(实际上DialogFragment这样说),当你在创建对话框视图后尝试给视图充气时会出现问题.您仍然可以在onCreateView中执行其他操作,例如使用savedInstanceState,而不会导致异常. (32认同)
  • 同样在这里.需要支持两者.这是使用片段内联或作为对话框的想法.对我来说似乎是一个错误.我能做的最好的事情是设置对话框的标题,但没有好运在onCreateDialog中添加取消按钮,通过调用super并将title设置为返回的对话框对象:final Dialog dialog = super.onCreateDialog(savedInstanceState); dialog.setTitle(m_callback.getTitle()); //没有运气添加取消按钮返回对话框; (2认同)

Sam*_*Sam 35

第一种方法适用于我...直到我想使用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();
Run Code Online (Sandbox Code Playgroud)

  • @gghuffer虽然这已经晚了4个月,但我不认为,这个Exception直接由上面的代码引起.更常见的是,在添加内容之后,人们会调用`requestFeature(...)`(或类似`requestWindowFeature(Window.FEATURE_NO_TITLE);`)(如异常消息已经声明的那样). (2认同)

Zep*_*hyr 32

下面的代码来自谷歌指南,所以答案是你在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你有链接吗? (2认同)

I'm*_*pid 16

以下是在Dialog Fragment中使用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();


    }
Run Code Online (Sandbox Code Playgroud)


Ste*_*e B 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;
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*ley 5

如果您希望轻松访问对话框属性(如标题和关闭按钮),但您还想使用自己的布局,则可以在覆盖onCreateDialog时将LayoutInflator与Builder一起使用.

@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();
}
Run Code Online (Sandbox Code Playgroud)