在 DialogFragment 中为 AlertDialog 膨胀自定义视图时出现问题
Posted
技术标签:
【中文标题】在 DialogFragment 中为 AlertDialog 膨胀自定义视图时出现问题【英文标题】:Problem inflating custom view for AlertDialog in DialogFragment 【发布时间】:2011-11-22 10:02:31 【问题描述】:我正在尝试使用AlertDialog
中的自定义视图创建DialogFragment
。这个视图必须是从 xml 扩展而来的。在我的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();
我已经为.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)
如果我尝试像这样使用DialogFragment
的getLayoutInflator(Bundle)
:
.setView(getLayoutInflater(savedInstanceState).inflate(R.layout.dialog, null))
我收到了***Error
。
有谁知道如何在DialogFragment
中为AlertDialog
扩展自定义视图?
【问题讨论】:
【参考方案1】:第一个错误行提示我这与您创建对话框的方式有关 - 而不是对话框本身。
您是自动创建对话框(这可能意味着在视图全部设置之前调用它)还是响应按钮单击?由于实例化顺序,我最初遇到了片段问题。
我使用与您相同的代码来设置视图,并且我的结果有效。我剪掉了其他设置以使其看起来更干净,但无论有没有它都可以使用。
@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();
【讨论】:
这对我有用,但我想了解原因。为什么 dialogFragment 的 getLayoutInflater 返回的 layoutinflater 与 Activity 的不同? 每个 LayoutInflater 都与一个上下文相关联(在 Activity 和片段之间有所不同),片段使事情变得复杂。此外,有一些东西不能递归地工作(例如对话中的对话)。我猜想问题出在实例化顺序和递归之间,但顺其自然而不是进一步挖掘可能更容易...... 这让我遇到了真正的问题,那就是你必须先调用setView()
(比如setTitle()
,这是我做错的)。谢谢。
一切都很好,但是现在没有显示正面和负面按钮。
这也适用于 DialogFragments testest【参考方案2】:
我对这些答案感到惊讶,因为它们都没有解决问题。
DialogFragment 允许您为对话框重复使用相同的 UI,并在其他地方作为片段集成到您的应用程序中。很实用的功能。根据谷歌的文档,您可以通过覆盖 onCreateDialog 和 onCreateView 来实现这一点。 http://developer.android.com/reference/android/app/DialogFragment.html
这里有三种情况:
-
仅覆盖 onCreateDialog - 用作对话框但不能
集成到其他地方。
仅覆盖 onCreateView - 不能用作对话框,但可以
集成到其他地方。
覆盖两者 - 用作对话框并且可以集成
其他地方。
解决方案: AlertDialog 类正在调用另一个调用 requestFeature 的类。要解决此问题.. 不要使用 AlertDialog,而是使用普通 Dialog 或 super.onCreateDialog 返回的任何内容。这是我发现的最佳解决方案。
警告: 其他对话框如 DatePickerDialog、ProgressDialog、TimePickerDialog 都继承自 AlertDialog 并且可能会导致相同的错误。
底线: 如果您需要创建需要在多个地方使用的非常定制的界面,DialogFragment 是很好的选择。重用现有的 android 对话框似乎不起作用。
【讨论】:
从实验结果来看,这个问题只发生在某些版本的 Android 上。已经看到它在 21 和 22 失败,而它在 23、24 工作。 使用普通对话框代替 AlertDialog 是我的答案。谢谢。 DialogFragment 的 documentation 表示onCreateDialog
"...对于创建 AlertDialog
最有用,允许您向用户显示由片段。"【参考方案3】:
避免请求功能崩溃并使用相同的布局:
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();
【讨论】:
仅供参考,您可以使用getShowsDialog()
了解您的片段是否显示为模态。但是看看@vangorra 的回答。
我知道这很旧,但我必须阅读很多关于这个和类似问题的答案,这是唯一提到你需要为模式对话框返回 super.onCreateView 的答案。谢谢。【参考方案4】:
我遇到了同样的问题。就我而言,这是因为 Android Studio 创建了一个模板 onCreateView,它重新膨胀了一个新视图,而不是返回在 onCreateDialog 中创建的视图。 onCreateView 是在 onCreateDialog 之后调用的,所以解决方案是简单地重新使用 Fragments 视图。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
return this.getView();
【讨论】:
【参考方案5】:遇到了同样的问题,花了很多时间来消除错误。最后将资源 ID 传递给 setView() 方法解决了这个问题。添加设置视图如下:
.setView(R.layout.dialog)
【讨论】:
如果您使用.setView(R.layout.dialog)
,而不是View view = getActivity().getLayoutInflater().inflate(R.layout.dialog, null); builder.setView(view);
,您将看到一个布局,但您将无法访问控件(视图)。因此,您不会添加addTextChangedListener
、setOnClickListener
等。【参考方案6】:
在你调用的代码中
create().
替换为
show().
【讨论】:
onCreateDialog()
应该返回一个Dialog
,这就是我使用.create()
的原因。 DialogFragment
由创建此DialogFragment
并将其添加到其FragmentManager
的片段显示 通过DialogFragment.show(FragmentTransaction, String)
【参考方案7】:
我没有从 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();
【讨论】:
【参考方案8】:您想要做的是像往常一样在 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(..);
瞧,一个带有您自己的自定义视图的对话框。
【讨论】:
不幸的是,这不允许您设置操作系统标准对话框按钮。 完全正确。由于对话框中没有操作栏,我完全依靠 AlertDialog 的按钮【参考方案9】:由于我需要很长时间来解决同样的问题(弹出一个简单的文本对话框),我决定分享我的解决方案:
布局文件connectivity_dialog.xml 包含一个带有消息文本的简单TextView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:gravity="center"
android:layout_gravity="center">
<TextView
android:layout_
android:layout_
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>
显示“对话框”的 Activity 实现了一个内部类(因为 DialogFragment 是一个片段而不是一个对话框;更多信息请参阅https://***.com/a/5607560/6355541)。 Activity 可以通过两个函数激活和停用 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");
【讨论】:
以上是关于在 DialogFragment 中为 AlertDialog 膨胀自定义视图时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
Grafana Alert/AzureMonitor:在 Grafana 中为图形创建警报规则时出现执行错误