创建自定义AlertDialog?什么是根视图?

17

我想做什么:

创建自定义警告对话框。按钮就像任何警告对话框一样,但上面有两个TextEdit输入框。我不想创建一个自定义的对话框,而是一个定制的警告对话框。

这是我正在尝试的第三种方法:http://developer.android.com/guide/topics/ui/dialogs.html

它说:

AlertDialog.Builder builder;
AlertDialog alertDialog;

Context mContext = getApplicationContext();
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.custom_dialog,
                           (ViewGroup) findViewById(R.id.layout_root));
TextView text = (TextView) layout.findViewById(R.id.text);
text.setText("Hello, this is a custom dialog!");


builder = new AlertDialog.Builder(mContext);
builder.setView(layout);
alertDialog = builder.create();

文档说明:

View layout = inflater.inflate(R.layout.custom_dialog,
                           (ViewGroup) findViewById(R.id.layout_root));

第一个参数是布局资源ID,第二个参数是根视图的ID。

问题是我不知道布局的根是什么? 我将在Activity中启动此对话框。 我应该使用活动的布局ID吗? layout_root是从哪里来的?

也尝试过:

  View layout = inflater.inflate(R.layout.my_custom_layout,
                                   (ViewGroup)   findViewById(android.R.id.content).getRootView());

结果是空指针。

4个回答

37

尽管这是一个较旧的问题,但对于那些正在寻找答案的人来说,本文可能仍有用处:

按意图进行布局膨胀

如果您曾经在Android应用程序中使用LayoutInflater编写以下类似代码:

inflater.inflate(R.layout.my_layout, null);

请继续阅读,因为您做错了,我想向您解释原因。

...但是...

每个规则都有例外

当然也有一些情况,你可以真正地为在解析布局时传递一个null的父布局来辩护,但这种情况很少见。其中一种情况出现在你想要将自定义布局填充到AlertDialog中作为对话框视图的情况下,请考虑以下示例:

AlertDialog.Builder builder = new AlertDialog.Builder(context);
View content = LayoutInflater.from(context).inflate(R.layout.item_row, null);

builder.setTitle("My Dialog");
builder.setView(content);
builder.setPositiveButton("OK", null);
builder.show();
问题在于AlertDialog.Builder支持自定义视图,但是不提供一个接受布局资源的setView()实现;因此,必须手动填充XML。然而,由于结果将进入对话框,而对话框不公开其根视图(事实上,它尚不存在),所以我们无法将其用作填充的父级。事实证明,这并不重要,因为AlertDialog将擦除布局中的所有LayoutParams,并将它们替换为match_parent。
本文解释了为什么在大多数情况下,除了构建对话框之外,您应该提供一个父ViewGroup。

1
这个答案非常完美!但是现在你可以使用支持库来设置资源ID,方法是https://developer.android.com/reference/android/support/v7/app/AlertDialog.Builder.html#setView(int)。然后,如果你想在任何视图中以编程方式添加一些行为,你只需要调用AlertDialog.findViewById(id)。为此,你应该调用Builder.setView(res) => Builder.show() => find(id)... 致敬! - Nahuel Barrios

1

你试过这个吗?

View layout = inflater.inflate(R.layout.custom_dialog,null);

View v = inflater.inflate(R.layout.activity_main, null); 会产生一个警告。使用 View.inflate(..., null, false) 只是隐藏了警告,但并没有解决问题。正确的方法是使用 builder.setView(R.layout.edit_account_dialog); dialog = builder.create(); 但是只有在活动调用 dialog.show() 后才能使用 findViewById;这又引起了另一个问题:对话框的 findViewByIdshow() 之前不可用,而在 show() 之后也不容易调用。顺便说一下,在 dialog.show() 后立即在活动中调用 findViewById 不是一个好的做法。 - JarsOfJam-Scheduler

1

好的。文档中的根视图是指自定义布局中的元素。因此,自定义布局将有一个名为根视图的最外层视图。您需要为其分配一个ID,然后可以按照所示传递它。因此,第一个参数是自定义视图ID,第二个参数是自定义视图中根布局元素的ID。

 View layout = inflater.inflate(R.layout.custom_dialog,
                       (ViewGroup) findViewById(R.id.layout_root));

因此,在上面的文档示例中,R.id.layout_root 是指您为 custom_dialog 布局中最外层 LinearLayout 给出的 ID。


0
builder.setView(layout);
layout.getRootView();

应该返回LinearLayout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接