Bố cục tùy chỉnh cho OnCreateView DialogFragment so với OnCreateDialog


81

Tôi đang cố gắng tạo DialogFragment bằng cách sử dụng Bố cục của riêng mình.

Tôi đã thấy một vài cách tiếp cận khác nhau. Đôi khi bố cục được đặt trong OnCreateDialog như thế này: (Tôi đang sử dụng Mono nhưng tôi đã quen với 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();
}

Cách tiếp cận đầu tiên này phù hợp với tôi ... cho đến khi tôi muốn sử dụng findViewByID. vì vậy sau một chút tìm hiểu trên Google, tôi đã thử cách tiếp cận thứ hai liên quan đến việc ghi đèOnCreateView

Vì vậy, tôi đã nhận xét ra hai dòng trong số OnCreateDialogđó đặt Bố cục và sau đó thêm dòng này:

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

điều này mang lại cho tôi một lỗi đáng yêu:

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

Tôi bối rối.


Quá muộn nhưng vẫn đăng tương tự: stackoverflow.com/questions/21258228/...
Raghav Sharma

Câu trả lời:


36

Cách tiếp cận đầu tiên này phù hợp với tôi ... cho đến khi tôi muốn sử dụng FindViewByID.

Tôi đoán rằng bạn không xác định phạm vi findViewById()Chế độ xem được trả về inflate(), hãy thử điều này:

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
Điều này thực sự hoạt động. Cảm ơn! Tôi vẫn tò mò là tại sao OnCreateView lại gặp sự cố.
gghuffer

2
@gghuffer Mặc dù đã trễ 4 tháng nhưng tôi không nghĩ rằng Ngoại lệ này là do đoạn mã trên trực tiếp gây ra. Phổ biến hơn là mọi người gọi requestFeature(...)(hoặc một cái gì đó tương tự requestWindowFeature(Window.FEATURE_NO_TITLE);) sau khi thêm nội dung (như thông báo Ngoại lệ đã nêu).
Griddo

54

Tôi đã có cùng một ngoại lệ với mã sau:

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

Bạn phải chọn chỉ ghi đè một trong các onCreateView hoặc onCreateDialog trong DialogFragment. Ghi đè cả hai sẽ dẫn đến ngoại lệ: "requestFeature () phải được gọi trước khi thêm nội dung".

Quan trọng

Để có câu trả lời đầy đủ, hãy kiểm tra nhận xét @TravisChristian. Như anh ấy đã nói, bạn thực sự có thể ghi đè cả hai, nhưng vấn đề xảy ra khi bạn cố gắng tăng chế độ xem sau khi đã tạo chế độ xem hộp thoại.


32
Điều đó không hoàn toàn đúng. Bạn có thể ghi đè cả hai (trên thực tế DialogFragment nói như vậy), vấn đề xảy ra khi bạn cố gắng tăng dạng xem sau khi đã tạo dạng xem hộp thoại. Bạn vẫn có thể làm những việc khác trong onCreateView, chẳng hạn như sử dụng SaveInstanceState mà không gây ra ngoại lệ.
Travis Christian

3
Ở đây cũng vậy. Cần hỗ trợ cả hai. Đó là ý tưởng sử dụng đoạn nội tuyến hoặc như một hộp thoại. Có vẻ như một lỗi đối với tôi. Điều tốt nhất tôi có thể làm, là đặt tiêu đề cho hộp thoại nhưng không may mắn khi thêm nút hủy trong onCreateDialog bằng cách gọi super và đặt tiêu đề cho đối tượng hộp thoại trả về: hộp thoại final Dialog = super.onCreateDialog (saveInstanceState); hộp thoại.setTitle (m_callback.getTitle ()); // không may mắn khi thêm hộp thoại trả lại nút hủy;
farid_z

33

Mã bên dưới đến từ hướng dẫn của google, vì vậy câu trả lời là bạn không thể làm như của bạn trong onCreateDialog (), bạn phải sử dụng super.onCreateDialog () để có được hộp thoại.

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
bạn có một liên kết?
Daniel Gomez Rico

@Zebphyr Điều gì xảy ra nếu tôi muốn sử dụng CustomDialogFragment này làm Hộp thoại cho hoạt động của mình, nhưng trong đoạn mã ở trên không có đề cập đến onCreateDialog()phương thức R.layout.my_layout . Sẽ onCreateView()giúp trong trường hợp này?
CopsOnRoad

@Jack Jan, Có, bạn có thể chỉ định tệp bố cục trong lệnh gọi onCreateView ().
Zephyr

16

Đây là một ví dụ về việc sử dụng findViewById trong một mảnh hộp thoại

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
Ví dụ này phù hợp với tôi một cách hoàn hảo. Bạn phải đặt tất cả mã của mình vào onCreateDialog thay vì từ onCreateView. Mã này cho phép người dùng làm điều đó cũng như nhận các nút. Hoàn hảo!
Brandon

10

Như @Xavier Egea đã nói, nếu bạn đã triển khai cả onCreateView () và onCreateDialog (), bạn có nguy cơ gặp sự cố "requestFeature () phải được gọi trước khi thêm nội dung". Điều này là do CẢ onCreateDialog () sau đó onCreateView () được gọi khi bạn hiển thị () phân đoạn đó dưới dạng hộp thoại (tại sao, tôi không biết). Như Travis Christian đã đề cập, giá trị phồng lên () trong onCreateView () sau khi hộp thoại được tạo trong onCreateDialog () là nguyên nhân gây ra lỗi.

Một cách để triển khai cả hai chức năng này, nhưng tránh sự cố này: sử dụng getShowsDialog () để giới hạn việc thực thi onCreateView () của bạn (vì vậy, hàm phồng () của bạn không được gọi). Bằng cách này, chỉ mã onCreateDialog () của bạn được thực thi khi bạn đang hiển thị DialogFragment dưới dạng hộp thoại, nhưng mã onCreateView () của bạn có thể được gọi khi DialogFragment của bạn đang được sử dụng như một phân đoạn trong một bố cục.

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

Tôi không nhìn thấy điểm trong việc này kể từ onCreateView được cấu hình xem anyways tại sao bạn muốn cấu hình xem tại cả hai nơi bạn có thể giữ onCreateView như mã lạm phát chung và rằng dù sao sẽ được thổi phồng trong hộp thoại
user1530779

@ user1530779 Còn các nút thì sao? trong OnCreateDialog, tôi có thể sử dụng trình tạo để đặt các nút và tôi phải làm gì trong OnCreateView để có được các nút khi chế độ xem được thổi phồng trong hộp thoại?
Varvara Kalinina

Hmm, có vẻ như việc sử dụng Builder cho tôi một ngoại lệ. Vậy cách thiết lập các nút sẽ như thế nào nếu chế độ xem bị thổi phồng trong hộp thoại và không đặt nút nào khi nó chỉ là một mảnh?
Varvara Kalinina

Vâng, nó chỉ ra rằng nếu bạn gọi dialog.setView thay vì dialog.setContentView phương pháp này hoạt động tốt ngay cả khi bạn tạo thoại của bạn với một Builder và bộ nút
Varvara Kalinina

6

Nếu bạn muốn dễ dàng truy cập vào các thuộc tính hộp thoại, như tiêu đề và nút loại bỏ, nhưng bạn cũng muốn sử dụng bố cục của riêng mình, bạn có thể sử dụng LayoutInflator với Builder của mình khi bạn ghi đè onCreateDialog.

@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();
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.