36

我正在尝试使用AlertDialog中的自定义视图创建DialogFragment。这个视图必须从xml中夸大。在我的DialogFragment I类有:在DialogFragment中为AlertDialog充气自定义视图问题

@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(); 
} 

我曾尝试.setView()其他充气的方法,如:

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

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

在作为片段设定目标片段后显示这个对话框。

所有这些企图夸大以下异常我的自定义视图结果:

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) 

而如果我尝试使用DialogFragmentgetLayoutInflator(Bundle)这样的:

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

我得到一个StackOverflowError

有谁知道如何在DialogFragment中膨胀AlertDialog的自定义视图吗?

回答

72

第一个错误行给我提示,这与您如何创建对话框有关 - 而不是对话框本身。

是否自动创建对话框(可能意味着在视图全部设置之前调用该对话框)或响应按钮单击?由于实例化顺序,我最初遇到了碎片问题。

我使用相同的代码来设置视图,因为你有我的结果。我删除了其他设置,使其看起来更清洁,但它可以与其他设备一起使用。

@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(); 
} 
+1

这对我有用,但我想明白为什么。为什么dialogFragment的getLayoutInflater会返回一个与Activity不同的layoutinflater? – stork

+0

每个LayoutInflater绑定到一个上下文(在Activity和片段之间有所不同),并且片断使事情变得复杂。此外,还有一些不能递归工作的东西(例如对话框中的对话框)。我猜想问题在于实例化顺序和递归之间的某处,但它可能更容易滚动,而不是进一步挖掘... – ProjectJourneyman

+15

这导致我真正的问题是你必须调用'setView()'之前(比如'setTitle()',这是我做错了)。谢谢。 – ashughes

0

在你的代码中调用

create(). 

show(). 
+2

'onCreateDialog()'应该返回一个'Dialog',这就是为什么我使用'.create()'。 'DialogFragment'由片段显示_shown_,它通过DialogFragment.show(FragmentTransaction,String)创建并将此DialogFragment添加到其'FragmentManager'中。 – ashughes

0

替换我还没有从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(); 
} 
0

你想要做的是在onCreateView方法中创建自定义视图,就像通常那样。如果你想做一些改变对话框标题的东西,你可以在onCreateView中做。

下面是一个例子来说明我的意思:

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

然后您只要致电:

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

瞧,用自己的自定义视图的对话框。

+5

不幸的是,这不允许你设置OS标准对话框按钮。准确地说是 –

+0

。由于您没有对话框中的操作栏,我完全依靠AlertDialog的按钮 – njzk2

20

我对这些问题的答案惊讶,因为他们没有解决问题。

DialogFragment允许您在对话框中重复使用相同的UI,并将其作为片段集成到其他应用程序中。相当有用的功能。根据谷歌的文档,你可以通过覆盖onCreateDialog和onCreateView来实现。 http://developer.android.com/reference/android/app/DialogFragment.html

有三种情况在这里:

  1. 只重写onCreateDialog - 作品的对话,但不能 别处集成。
  2. 仅覆盖onCreateView - 不能用作对话框,但可以在其他位置集成 。
  3. 覆盖两个 - 作为对话框工作,并可以在其他地方集成 。

解决方案: 的AlertDialog类调用另一个类调用requestFeature。要解决这个问题..不要使用AlertDialog,而应使用普通的Dialog或任何super.onCreateDialog返回的值。这个我找到的解决方案效果最好。

警告: 其他对话框如DatePickerDialog,ProgressDialog,TimePickerDialog都会从AlertDialog继承,并且可能会导致相同的错误。

底线: 如果您需要创建非常需要在多个位置使用的定制界面,DialogFragment非常好。它似乎不能重用现有的android对话框。

+0

从实验中,这个问题只发生在某些Android版本上。已经看到它在21日和22日失败,而它在23日和24日工作。 –

10

避免请求功能部件的碰撞,并使用相同的布局:

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(); 
    } 
} 
+1

这是我见过的最好的解决方案。 –

+2

仅供参考,您可以使用'getShowsDialog()'来知道您的片段是否显示为模态。但看@vangorra答案。 – Neige

2

我有同样的问题。在我的情况下,这是因为Android Studio创建了一个onCreateView模板,用于重新填充新视图,而不是返回在onCreateDialog中创建的视图。 onCreateView是在onCreateDialog之后调用的,因此解决方案是简单地重新生成片段视图。

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

这解决了我的问题! –

1

面对同样的问题,并且花了很多时间摆脱错误。最后传递资源ID到setView()方法解决了这个问题。添加设置如下图:

.setView(R.layout.dialog)

+0

请使用代码标记来提高可读性。 –

0

因为我需要很长的时间来解决同样的问题(弹出一个简单的文本对话框),我决定分享我的解决方案:

的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> 

表示“对话”活动实现内部类(如DialogFragment是片段,而不是一个对话;进一步信息参见https://stackoverflow.com/a/5607560/6355541)。该活动可以通过两个功能激活和停用DialogFragment。如果您使用的是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"); 
} 
相关问题