【问题标题】:How to implement a custom AlertDialog View如何实现自定义的 AlertDialog 视图
【发布时间】: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();

【问题讨论】:

  • 要在对话框中查找和使用您的对象,请按照以下四个步骤操作:stackoverflow.com/a/18773261/1699586
  • 一站式回答:将.setView(getLayoutInflater().inflate(R.layout.dialog_view, null))添加到构建器。归功于下面的 Sergio Viudes。

标签: android android-alertdialog


【解决方案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_width="fill_parent"
              android:layout_height="wrap_content"
              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_width="match_parent"
          android:layout_height="match_parent">

<EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/password_edit_view"
        android:inputType="textPassword"/>
<CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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_width="match_parent"
                  android:layout_height="match_parent">
    
        <EditText
            android:id="@+id/editText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    
    </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 中所述。

    另见

    【讨论】:

    • 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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2023-04-11
            • 1970-01-01
            • 2020-08-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-12-10
            相关资源
            最近更新 更多