简体   繁体   English

在DialogFragment中为AlertDialog增加自定义视图的问题

[英]Problem inflating custom view for AlertDialog in DialogFragment

I'm trying to create a DialogFragment using a custom view in an AlertDialog . 我正在尝试使用DialogFragment中的自定义视图创建AlertDialog This view must be inflated from xml. 必须从xml中扩充此视图。 In my DialogFragment class I have: 在我的DialogFragment类中,我有:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new AlertDialog.Builder(getActivity())
        .setTitle("Title")
        .setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, null))
        .setPositiveButton(android.R.string.ok, this)
        .setNegativeButton(android.R.string.cancel, null)
        .create();
}

I have tried other inflation methods for .setView() such as: 我已经尝试过.setView()其他通胀方法,例如:

.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getView(), false))

and

.setView(getActivity().getLayoutInflater().inflate(R.layout.dialog, (ViewGroup) getTargetFragment().getView(), false))

After setting the target fragment in the fragment that is showing this dialog. 在显示此对话框的片段中设置目标片段之后。

All of these attempts to inflate my custom view result in the following exception: 所有这些尝试使我的自定义视图膨胀都会导致以下异常:

E/AndroidRuntime(32352): android.util.AndroidRuntimeException: requestFeature() must be called before adding content
E/AndroidRuntime(32352):        at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:214)
E/AndroidRuntime(32352):        at com.android.internal.app.AlertController.installContent(AlertController.java:248)
E/AndroidRuntime(32352):        at android.app.AlertDialog.onCreate(AlertDialog.java:314)
E/AndroidRuntime(32352):        at android.app.Dialog.dispatchOnCreate(Dialog.java:335)
E/AndroidRuntime(32352):        at android.app.Dialog.show(Dialog.java:248)
E/AndroidRuntime(32352):        at android.support.v4.app.DialogFragment.onStart(DialogFragment.java:339)
E/AndroidRuntime(32352):        at android.support.v4.app.Fragment.performStart(Fragment.java:1288)
E/AndroidRuntime(32352):        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:873)
E/AndroidRuntime(32352):        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1041)
E/AndroidRuntime(32352):        at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:625)
E/AndroidRuntime(32352):        at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1360)
E/AndroidRuntime(32352):        at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:411)
E/AndroidRuntime(32352):        at android.os.Handler.handleCallback(Handler.java:587)
E/AndroidRuntime(32352):        at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime(32352):        at android.os.Looper.loop(Looper.java:132)
E/AndroidRuntime(32352):        at android.app.ActivityThread.main(ActivityThread.java:4028)
E/AndroidRuntime(32352):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(32352):        at java.lang.reflect.Method.invoke(Method.java:491)
E/AndroidRuntime(32352):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
E/AndroidRuntime(32352):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
E/AndroidRuntime(32352):        at dalvik.system.NativeStart.main(Native Method)

While if I try to use the DialogFragment 's getLayoutInflator(Bundle) like this: 如果我尝试使用DialogFragmentgetLayoutInflator(Bundle)如下所示:

.setView(getLayoutInflater(savedInstanceState).inflate(R.layout.dialog, null))

I get a StackOverflowError . 我得到一个StackOverflowError

Does anyone know how to inflate a custom view for an AlertDialog in a DialogFragment ? 有谁知道如何在AlertDialog中为DialogFragment充气自定义视图?

The first error line gives me the hint that this is related to how you are creating your dialog - not the dialog itself. 第一个错误行给了我一个暗示,这与你如何创建对话框有关 - 而不是对话框本身。

Are you creating the dialog automatically (which could mean this gets called before the views are all set up) or in response to a button click? 您是自动创建对话框(可能意味着在视图全部设置之前调用此对话框)还是响应按钮单击? I initially had problems with fragments due to instantiation order. 由于实例化顺序,我最初遇到碎片问题。

I used the same code to set the view as you have, and my result works. 我使用相同的代码来设置视图,我的结果是有效的。 I cut out the other setup to make this look cleaner, but it works with or without it. 我删除了其他设置,使其看起来更干净,但它可以使用或不使用它。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

    View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_layout, null);
    builder.setView(view);

    return builder.create();
}

I'm surprised by these answers as none of them solve the problem. 我对这些答案感到惊讶,因为他们都没有解决问题。

A DialogFragment allows you to reuse the same UI for both a dialog and integrated in your app elsewhere as a fragment. DialogFragment允许您为对话框重用相同的UI,并将其作为片段集成到您的app中。 Quite a useful feature. 相当有用的功能。 As per google's documentation, you can achieve this by overriding onCreateDialog and onCreateView. 根据谷歌的文档,你可以通过覆盖onCreateDialog和onCreateView来实现这一点。 http://developer.android.com/reference/android/app/DialogFragment.html http://developer.android.com/reference/android/app/DialogFragment.html

There are three scenarios here: 这里有三种情况:

  1. Override onCreateDialog only - Works as a dialog but cannot be integrated elsewhere. 仅覆盖onCreateDialog - 作为对话框工作,但不能在其他地方集成。
  2. Override onCreateView only - Does not work as a dialog but can be integrated elsewhere. 仅覆盖onCreateView - 不能用作对话框,但可以集成到其他位置。
  3. Override both - Works as a dialog and can be integrated elsewhere. 覆盖两者 - 作为对话框工作,可以集成到其他地方。

Solution: The AlertDialog class is calling another class which calls requestFeature. 解决方案:AlertDialog类正在调用另一个调用requestFeature的类。 To fix this.. Don't use the AlertDialog, instead use a plain Dialog or whatever super.onCreateDialog returns. 解决这个问题。不要使用AlertDialog,而是使用普通的Dialog或super.onCreateDialog返回的任何内容。 This the solution that I have found works best. 这个我找到的解决方案效果最好。

Caveat: Other dialogs such as DatePickerDialog, ProgressDialog, TimePickerDialog all inherit from AlertDialog and will likely cause the same error. 警告:其他对话框,如DatePickerDialog,ProgressDialog,TimePickerDialog都继承自AlertDialog,可能会导致相同的错误。

Bottom Line: DialogFragment is good if you need to create very customized interface that needs to be used in several places. 结论:如果您需要创建需要在多个地方使用的非常自定义的界面,DialogFragment是很好的。 It doesn't appear to work to reuse existing android dialogs. 它似乎无法重用现有的android对话框。

Avoid request feature crash and use same layout: 避免请求功能崩溃并使用相同的布局:

public class MyCombinedFragment extends DialogFragment
{
    private boolean isModal = false;

    public static MyCombinedFragment newInstance()
    {
        MyCombinedFragment frag = new MyCombinedFragment();
        frag.isModal = true; // WHEN FRAGMENT IS CALLED AS A DIALOG SET FLAG
        return frag;
    }

    public MyCombinedFragment()
    {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    {
        if(isModal) // AVOID REQUEST FEATURE CRASH
        {
        return super.onCreateView(inflater, container, savedInstanceState);
        }
        else
        {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);
        setupUI(view);
        return view;
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        AlertDialog.Builder alertDialogBuilder = null;
        alertDialogBuilder = new AlertDialog.Builder(getActivity());
        View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_layout, null);
        alertDialogBuilder.setView(view);
        alertDialogBuilder.setTitle(“Modal Dialog“);
        alertDialogBuilder.setPositiveButton("Cancel", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                dialog.dismiss();
            }
        });
        setupUI(view);
        return alertDialogBuilder.create();
    }
}

I had the same problem. 我有同样的问题。 In my case it was becasue Android Studio created a template onCreateView that re-inflated a new view instead of returning the view created in onCreateDialog. 在我的例子中,因为Android Studio在创建了一个模板onCreateView,它重新夸大了一个新视图而不是返回在onCreateDialog中创建的视图。 onCreateView is called after onCreateDialog, so the solution was to simply reurnt the fragments view. 在onCreateDialog之后调用onCreateView,因此解决方案是简单地重新访问片段视图。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return this.getView();
}

Faced the same issue, and it took lot of time to get rid of the error. 面对同样的问题,花了很多时间来摆脱错误。 Finally passing resource ID to setView() method solved the problem. 最后将资源ID传递给setView()方法解决了这个问题。 Add set view as below: 添加设置视图如下:

.setView(R.layout.dialog)

As i needed long time for solving the same problem (Pop up a simple Text Dialog) i decided to share my solution: 由于我需要很长时间来解决同样的问题(弹出一个简单的文本对话框)我决定分享我的解决方案:

The layoutfile connectivity_dialog.xml contains a simple TextView with the message text: layoutfile connectivity_dialog.xml包含一个带有消息文本的简单TextView:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:gravity="center"
              android:layout_gravity="center">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:text="Connectivity was lost"
        android:textSize="34sp"
        android:gravity="center"
        />
</RelativeLayout>

The Activity showing the "dialog" implements a inner class (as DialogFragment is a Fragment and not a Dialog; further info see https://stackoverflow.com/a/5607560/6355541 ). 显示“对话框”的活动实现了一个内部类(因为DialogFragment是片段而不是对话框;更多信息请参阅https://stackoverflow.com/a/5607560/6355541 )。 The Activity can activate and deactivate the DialogFragment via two functions. Activity可以通过两个函数激活和取消激活DialogFragment。 If you're using android.support.v4, you may want to change to getSupportFragmentManager(): 如果您使用的是android.support.v4,则可能需要更改为getSupportFragmentManager():

public static class ConnDialogFragment extends DialogFragment {
    public static ConnDialogFragment newInstance() {
        ConnDialogFragment cdf = new ConnDialogFragment();
        cdf.setRetainInstance(true);
        cdf.setCancelable(false);
        return cdf;
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.connectivity, container, false);
    }
}

private void dismissConn() {
    DialogFragment df = (DialogFragment) getFragmentManager().findFragmentByTag("conn");
    if (df != null) df.dismiss();
}

private void showConn() {
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment prev = getFragmentManager().findFragmentByTag("conn");
    if (prev != null) ft.remove(prev);
    ft.addToBackStack(null);
    ConnDialogFragment cdf = ConnDialogFragment.newInstance();
    cdf.show(ft, "conn");
}

In your code where you call 在您调用的代码中

 create().

Replace with 用。。。来代替

show().

I haven't inflated from XML but I have done dynamic view generation in a DialogFragment successfully: 我没有从XML中膨胀,但我在DialogFragment中成功完成了动态视图生成:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    m_editText = new EditText(getActivity());
    return new AlertDialog.Builder(getActivity())
            .setView(m_editText)
            .setPositiveButton(android.R.string.ok,null)
            .setNegativeButton(android.R.string.cancel, null);
            .create();
}

What you want to do instead is create your custom view in the onCreateView method like you normally would. 你想要做的是像往常一样在onCreateView方法中创建自定义视图。 If you want to do something like change the title of the dialog, you do that in onCreateView. 如果您想要更改对话框的标题,可以在onCreateView中执行此操作。

Here's an example to illustrate what I mean: 这是一个例子来说明我的意思:

        @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        getDialog().setTitle("hai");
        View v = inflater.inflate(R.layout.fragment_dialog, container, false);
        return v;
    }

Then you just call: 然后你打电话:

DialogFragment df = new MyDialogFragment();
df.show(..);

And voila, a dialog with your own custom view. 瞧,这是一个带有你自己的自定义视图的对话框。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM