如何实现自定义的 AlertDialog 视图
Posted
技术标签:
【中文标题】如何实现自定义的 AlertDialog 视图【英文标题】:How to implement a custom AlertDialog View 【发布时间】:2011-02-17 05:27:18 【问题描述】:在android docs on AlertDialog 中,它提供了以下说明和示例,用于在 AlertDialog 中设置自定义视图:
如果您想显示更复杂的视图,请查找名为“body”的 FrameLayout 并将您的视图添加到其中:
FrameLayout fl = (FrameLayout) findViewById(R.id.body);
fl.add(myView, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
首先,很明显add()
是一个错字,应该是addView()
。
我对使用 R.id.body 的第一行感到困惑。它似乎是 AlertDialog 的主体元素......但我不能只在我的代码 b/c 中输入它,它会给出编译错误。 R.id.body 是在哪里定义或分配的?
这是我的代码。我尝试在构建器上使用setView(findViewById(R.layout.whatever)
,但它不起作用。我假设是因为我没有手动充气?
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
.setCancelable(false)
.setPositiveButton("Go", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int id)
EditText textBox = (EditText) findViewById(R.id.textbox);
doStuff();
);
FrameLayout f1 = (FrameLayout)findViewById(R.id.body /*CURRENTLY an ERROR*/);
f1.addView(findViewById(R.layout.dialog_view));
AlertDialog alert = builder.create();
alert.show();
【问题讨论】:
要在对话框中查找和使用您的对象,请按照以下四个步骤操作:***.com/a/18773261/1699586 一站式回答:将.setView(getLayoutInflater().inflate(R.layout.dialog_view, null))
添加到构建器。归功于下面的 Sergio Viudes。
【参考方案1】:
您可以直接从 Layout Inflater 创建您的视图,您只需要使用您的布局 XML 文件的名称和文件中的布局 ID。
您的 XML 文件应具有如下 ID:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_layout_root"
android:orientation="vertical"
android:layout_
android:layout_
android:padding="10dp"
/>
然后您可以使用以下代码在构建器上设置布局:
LayoutInflater inflater = getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.dialog_layout, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dialoglayout);
builder.show();
【讨论】:
在这个例子中,R.id.dialog_layout_root 在哪里?这不是当前Activity中的视图吗? @AlexPretzlav:此示例中不需要 dialog_layout_root。您所需要的只是 R.layout.[name_of_xml_file] 的 xml 文件的名称。 @Temperage 你最后加了builder.show吗。我尝试了这段代码,它奏效了。我也将 null 作为 infalter.inflate 的第二个参数传递 这应该被选为最佳答案。 当自定义布局包含 EditText 时,这会产生 ClassCastException,因为getCurrentFocus()
将返回 EditText 并且 EditText 无法转换为 ViewGroup。使用null
作为第二个参数可以解决这个问题。【参考方案2】:
你是对的,这是因为你没有手动充气。您似乎正在尝试从 Activity 的布局中“提取”“body”id,但这是行不通的。
你可能想要这样的东西:
LayoutInflater inflater = getLayoutInflater();
FrameLayout f1 = (FrameLayout)alert.findViewById(android.R.id.body);
f1.addView(inflater.inflate(R.layout.dialog_view, f1, false));
【讨论】:
有趣的是,body 没有在 android.R.id 中定义为常量。我仍然不清楚如何访问创建的 AlertDialog 的“body”元素。我仍然想知道如何做到这一点,但现在我将尝试扩充视图并在构建器中使用 setView。 实际上这仍然给我留下了一个问题(我是膨胀视图的新手)。使用builder.setView(inflater.inflate(R.id.dialog, ROOT_VIEWGROUP[, ATTACH_TO_ROOT]))
,文档说根视图组是可选的。在这种情况下应该使用它吗?如果是这样......仍然必须弄清楚如何获得对 AlertDialog 的引用......
它是可选的,但是你不会从你正在膨胀的布局内部获得对父级的引用。像 android:layout_gravity 这样的东西在顶层视图上不起作用......也许你不需要它们。当您调用 AlertDialog alert = builder.create() 时,您将获得对 AlertDialog 的引用。长答案简短,它是可选的。试一试,这取决于您在自定义布局中所做的工作,它可能会起作用。
我不清楚如何在 AlertDialog 中引用 view。如果我确实想引用父母,你会建议在这种情况下做什么?我在 alertDialog 中看到的唯一返回视图的是 getCurrentFocus()
握住View
你膨胀了。当您需要其内容中的内容时,请在 View
上致电 findViewById()
。见:github.com/commonsguy/cw-android/tree/master/Database/Constants【参考方案3】:
android.R.id.custom 为我返回 null。如果有人遇到同样的问题,我设法让它工作,
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle("My title")
.setMessage("Enter password");
final FrameLayout frameView = new FrameLayout(context);
builder.setView(frameView);
final AlertDialog alertDialog = builder.create();
LayoutInflater inflater = alertDialog.getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.simple_password, frameView);
alertDialog.show();
作为参考,R.layout.simple_password 是:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_
android:layout_>
<EditText
android:layout_
android:layout_
android:id="@+id/password_edit_view"
android:inputType="textPassword"/>
<CheckBox
android:layout_
android:layout_
android:text="@string/show_password"
android:id="@+id/show_password_checkbox"
android:layout_gravity="left|center_vertical"
android:checked="false"/>
</LinearLayout>
【讨论】:
约翰·瑞利斯。您的解决方案工作正常。只要有东西在里面。我们应该在 builder.create 之前充气并设置 frameView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));或首先,这将防止一些意外的错误 感谢您的反馈。您如何在 builder.create() 之前进行充气?在对话框的充气器上调用了 inflate,我只有一个对话框,因为我调用了 builder.create() 我们可以使用activity inflater,而不是附加到FrameLayout,所以我们可以像这样减少一些代码。AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), android.R .style.Theme_Holo)) .setTitle("title") .setIcon(R.drawable.sample_icon);查看 TroubleView = inflater.inflate(R.layout.sample_layout, null, false); builder.setView(troubleView);警报 = builder.create();对不起,我不知道如何在评论中清楚地编写代码 这只是一个设计错误,如果我们在布局xml中收集所有内容并忘记Framelayout作为对话框的根,我们可能会好奇xml中的布局是否没有填充父或什么,只是一个案例。 为我工作,谢谢!这使我能够添加标题和我的取消和确定按钮,包括没有错误的 EditText。 :) 唯一的问题是,这是如何工作的?FrameLayout
是否充当某种片段?当我在上面尝试 Andrewx2 的答案时,我得到了一个错误,因为它认为我在夸大两个布局(是我的猜测)。【参考方案4】:
android 文档已被编辑以纠正错误。
AlertDialog 内的视图称为android.R.id.custom
http://developer.android.com/reference/android/app/AlertDialog.html
【讨论】:
【参考方案5】:自定义警报对话框
此完整示例包括将数据传回 Activity。
创建自定义布局
这个简单的例子使用了带有EditText
的布局,但是你可以用任何你喜欢的东西来替换它。
custom_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:layout_
android:layout_>
<EditText
android:id="@+id/editText"
android:layout_
android:layout_/>
</LinearLayout>
在代码中使用对话框
关键部分是
使用setView
将自定义布局分配给AlertDialog.Builder
单击对话框按钮时将任何数据发送回活动。
这是上图所示示例项目的完整代码:
MainActivity.java
public class MainActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
public void showAlertDialogButtonClicked(View view)
// create an alert builder
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Name");
// set the custom layout
final View customLayout = getLayoutInflater().inflate(R.layout.custom_layout, null);
builder.setView(customLayout);
// add a button
builder.setPositiveButton("OK", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
// send data from the AlertDialog to the Activity
EditText editText = customLayout.findViewById(R.id.editText);
sendDialogDataToActivity(editText.getText().toString());
);
// create and show the alert dialog
AlertDialog dialog = builder.create();
dialog.show();
// do something with the data coming from the AlertDialog
private void sendDialogDataToActivity(String data)
Toast.makeText(this, data, Toast.LENGTH_SHORT).show();
注意事项
如果您发现自己在多个地方使用它,请考虑创建一个DialogFragment
子类,如documentation 中所述。
另见
Android Alert Dialog with one, two, and three buttons How can I display a list view in an Android Alert Dialog?【讨论】:
EditText editText = customLayout.findViewById(R.id.editText);
应该是EditText editText = (EditText) customLayout.findViewById(R.id.editText);
@philcruz,如果升级到 Android Studio 3.0,则不再需要显式转换视图。 IDE 可以推断类型。这是一个非常好的功能。对清理代码很有帮助。
很好的答案,真的很有帮助【参考方案6】:
这对我有用:
dialog.setView(dialog.getLayoutInflater().inflate(R.layout.custom_dialog_layout, null));
【讨论】:
【参考方案7】:对我有用的最简单的代码行如下:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(R.layout.layout_resource_id);
builder.show();
无论哪种类型的布局(LinearLayout、FrameLayout、RelativeLayout)都适用于setView
并且只会在外观和行为上有所不同。
【讨论】:
棒极了,简单易行【参考方案8】:最简单的方法是使用android.support.v7.app.AlertDialog
而不是android.app.AlertDialog
,其中public AlertDialog.Builder setView (int layoutResId)
可以在API 21 下使用。
new AlertDialog.Builder(getActivity())
.setTitle(title)
.setView(R.layout.dialog_basic)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int whichButton)
//Do something
)
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int whichButton)
//Do something
)
.create();
【讨论】:
在 API 21 引入后阅读此内容的任何人都应使用此方法。如答案所述,如果您的应用 minSDKversion 小于 21,请使用支持包中的 AlerDialog。瞧!!!【参考方案9】:AlertDialog.setView(View view)
确实将给定视图添加到R.id.custom FrameLayout
。以下是来自AlertController.setupView()
的Android 源代码的sn-p,它最终处理了这个问题(mView
是给AlertDialog.setView
方法的视图)。
...
FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.**custom**);
custom.addView(**mView**, new LayoutParams(FILL_PARENT, FILL_PARENT));
...
【讨论】:
【参考方案10】:在将 ID 更改为 android.R.id.custom 后,我需要添加以下内容以显示要显示的视图:
((View) f1.getParent()).setVisibility(View.VISIBLE);
但是,这导致新视图在没有背景的大父视图中呈现,将对话框分成两部分(文本和按钮,新视图介于两者之间)。通过在消息旁边插入我的视图,我终于得到了我想要的效果:
LinearLayout f1 = (LinearLayout)findViewById(android.R.id.message).getParent().getParent();
我通过使用 View.getParent() 和 View.getChildAt(int) 探索视图树找到了这个解决方案。不过,两者都不是很高兴。 Android 文档中没有这些内容,如果他们改变了 AlertDialog 的结构,这可能会中断。
【讨论】:
【参考方案11】:这样做最有意义,代码量最少。
new AlertDialog.Builder(this).builder(this)
.setTitle("Title")
.setView(R.id.dialog_view) //notice this setView was added
.setCancelable(false)
.setPositiveButton("Go", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int id)
EditText textBox = (EditText) findViewById(R.id.textbox);
doStuff();
).show();
要查看您可以设置的扩展列表,请开始在 Android Studio 中输入 .set
【讨论】:
以上是关于如何实现自定义的 AlertDialog 视图的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Xamarin Android 的 AlertDialog 中创建带有自定义适配器的列表视图
如何在 ListView 和 AlertDialog 中设置自定义字体?