如何实现自定义AlertDialog视图

时间:2021-09-27 18:59:30

In the Android docs on AlertDialog, it gives the following instruction and example for setting a custom view in an AlertDialog:

在AlertDialog的Android docs中,给出了在AlertDialog中设置自定义视图的指令和示例:

If you want to display a more complex view, look up the FrameLayout called "body" and add your view to it:

FrameLayout fl = (FrameLayout) findViewById(R.id.body);
fl.add(myView, new LayoutParams(FILL_PARENT, WRAP_CONTENT));

First off, it's pretty obvious that add() is a typo and is meant to be addView().

首先,很明显,add()是一个输入错误,应该是addView()。

I'm confused by the first line using R.id.body. It seems that it's the body element of the AlertDialog ... but I can't just enter that in my code b/c it gives a compile error. Where does R.id.body get defined or assigned or whatever?

我被第一行用r。id。body搞糊涂了。好像是AlertDialog的body元素……但是我不能在代码b/c中输入它会产生编译错误。R.id哪里。身体被定义,分配或者其他什么?

Here's my code. I tried to use setView(findViewById(R.layout.whatever) on the builder but it didn't work. I'm assuming because I didn't manually inflate it?

这是我的代码。我试图在构建器上使用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();

11 个解决方案

#1


47  

You are correct, it's because you didn't manually inflate it. It appears that you're trying to "extract" the "body" id from your Activity's layout, and that won't work.

你是对的,那是因为你没有手动充气。看起来,您试图从活动的布局中“提取”“body”id,这是行不通的。

You probably want something like this:

你可能想要这样的东西:

LayoutInflater inflater = getLayoutInflater();
FrameLayout f1 = (FrameLayout)alert.findViewById(android.R.id.body);
f1.addView(inflater.inflate(R.layout.dialog_view, f1, false));

#2


154  

You can create your view directly from the Layout Inflater, you only need to use the name of your layout XML file and the ID of the layout in file.

可以直接从布局扩展器创建视图,只需使用布局XML文件的名称和文件中的布局ID。

Your XML file should have an ID like this:

您的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"
              />

And then you can set your layout on the builder with the following code:

然后您可以在构建器上设置布局,代码如下:

LayoutInflater inflater = getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.dialog_layout, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dialoglayout);
builder.show();

#3


18  

android.R.id.custom was returning null for me. I managed to get this to work in case anybody comes across the same issue,

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

For reference, R.layout.simple_password is :

供参考,出来。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>

#4


17  

The android documents have been edited to correct the errors.

android文档经过编辑以纠正错误。

The view inside the AlertDialog is called android.R.id.custom

AlertDialog内部的视图称为android.r.d id.custom

http://developer.android.com/reference/android/app/AlertDialog.html

http://developer.android.com/reference/android/app/AlertDialog.html

#5


11  

This worked for me:

这工作对我来说:

dialog.setView(dialog.getLayoutInflater().inflate(R.layout.custom_dialog_layout, null));

#6


4  

The simplest lines of code that works for me are are follows:

对我来说最简单的代码行是:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(R.layout.layout_resource_id);
builder.show();

Whatever the type of layout(LinearLayout, FrameLayout, RelativeLayout) will work by setView and will just differ in the appearance and behavior.

无论布局的类型(线性布局、框架布局、相对论布局)如何,setView都可以工作,只是在外观和行为上有所不同。

#7


2  

AlertDialog.setView(View view) does add the given view to the R.id.custom FrameLayout. The following is a snippet of Android source code from AlertController.setupView() which finally handles this (mView is the view given to AlertDialog.setView method).

AlertDialog。setView(视图视图)确实将给定的视图添加到r id。自定义FrameLayout。下面是AlertController.setupView()的Android源代码片段,它最终处理了这个问题(mView是用于AlertDialog的视图)。setView方法)。

...
FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.**custom**);
custom.addView(**mView**, new LayoutParams(FILL_PARENT, FILL_PARENT));
...

#8


2  

The easiest way to do this is by using android.support.v7.app.AlertDialog instead of android.app.AlertDialog where public AlertDialog.Builder setView (int layoutResId) can be used below API 21.

最简单的方法是使用android.support.v7.app。AlertDialog代替android.app。AlertDialog公共AlertDialog的地方。生成器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();

#9


1  

After changing the ID it android.R.id.custom, I needed to add the following to get the View to display:

在改变ID之后,它是android.R.id。自定义,我需要添加以下内容来显示视图:

((View) f1.getParent()).setVisibility(View.VISIBLE);

However, this caused the new View to render in a big parent view with no background, breaking the dialog box in two parts (text and buttons, with the new View in between). I finally got the effect that I wanted by inserting my View next to the message:

但是,这导致新视图在没有背景的大父视图中呈现,将对话框分成两部分(文本和按钮,中间有新视图)。我终于得到了我想要的效果,在消息旁边插入我的视图:

LinearLayout f1 = (LinearLayout)findViewById(android.R.id.message).getParent().getParent();

I found this solution by exploring the View tree with View.getParent() and View.getChildAt(int). Not really happy about either, though. None of this is in the Android docs and if they ever change the structure of the AlertDialog, this might break.

我通过使用View. getparent()和View. getchildat (int)探索视图树找到了这个解决方案。不过,这两件事我都不太满意。这些都不在Android文档中,如果他们改变了AlertDialog的结构,这可能会失败。

#10


0  

Custom AlertDialog

This full example includes passing data back to the Activity.

这个完整的示例包括向活动传递数据。

如何实现自定义AlertDialog视图

Create a custom layout

A layout with an EditText is used for this simple example, but you can replace it with anything you like.

这个简单的示例使用了一个带有EditText的布局,但是您可以用您喜欢的任何东西替换它。

custom_layout.xml

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>

Use the dialog in code

The key parts are

的关键部分

  • using setView to assign the custom layout to the AlertDialog.Builder
  • 使用setView将自定义布局分配给AlertDialog.Builder
  • sending any data back to the activity when a dialog button is clicked.
  • 当单击对话框按钮时,将任何数据发送回活动。

This is the full code from the example project shown in the image above:

这是上面图片所示的示例项目的完整代码:

MainActivity.java

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

Notes

  • If you find yourself using this in multiple places, then consider making a DialogFragment subclass as is described in the documentation.
  • 如果您发现自己在多个地方都在使用它,那么请考虑按照文档中描述的那样创建一个DialogFragment子类。

See also

#11


0  

It would make the most sense to do it this way, least amount of code.

这样做最有意义,最少的代码量。

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

For an expanded list of things you can set, start typing .set in Android Studio

要查看可设置的扩展列表,请在Android Studio中输入.set

#1


47  

You are correct, it's because you didn't manually inflate it. It appears that you're trying to "extract" the "body" id from your Activity's layout, and that won't work.

你是对的,那是因为你没有手动充气。看起来,您试图从活动的布局中“提取”“body”id,这是行不通的。

You probably want something like this:

你可能想要这样的东西:

LayoutInflater inflater = getLayoutInflater();
FrameLayout f1 = (FrameLayout)alert.findViewById(android.R.id.body);
f1.addView(inflater.inflate(R.layout.dialog_view, f1, false));

#2


154  

You can create your view directly from the Layout Inflater, you only need to use the name of your layout XML file and the ID of the layout in file.

可以直接从布局扩展器创建视图,只需使用布局XML文件的名称和文件中的布局ID。

Your XML file should have an ID like this:

您的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"
              />

And then you can set your layout on the builder with the following code:

然后您可以在构建器上设置布局,代码如下:

LayoutInflater inflater = getLayoutInflater();
View dialoglayout = inflater.inflate(R.layout.dialog_layout, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dialoglayout);
builder.show();

#3


18  

android.R.id.custom was returning null for me. I managed to get this to work in case anybody comes across the same issue,

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

For reference, R.layout.simple_password is :

供参考,出来。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>

#4


17  

The android documents have been edited to correct the errors.

android文档经过编辑以纠正错误。

The view inside the AlertDialog is called android.R.id.custom

AlertDialog内部的视图称为android.r.d id.custom

http://developer.android.com/reference/android/app/AlertDialog.html

http://developer.android.com/reference/android/app/AlertDialog.html

#5


11  

This worked for me:

这工作对我来说:

dialog.setView(dialog.getLayoutInflater().inflate(R.layout.custom_dialog_layout, null));

#6


4  

The simplest lines of code that works for me are are follows:

对我来说最简单的代码行是:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(R.layout.layout_resource_id);
builder.show();

Whatever the type of layout(LinearLayout, FrameLayout, RelativeLayout) will work by setView and will just differ in the appearance and behavior.

无论布局的类型(线性布局、框架布局、相对论布局)如何,setView都可以工作,只是在外观和行为上有所不同。

#7


2  

AlertDialog.setView(View view) does add the given view to the R.id.custom FrameLayout. The following is a snippet of Android source code from AlertController.setupView() which finally handles this (mView is the view given to AlertDialog.setView method).

AlertDialog。setView(视图视图)确实将给定的视图添加到r id。自定义FrameLayout。下面是AlertController.setupView()的Android源代码片段,它最终处理了这个问题(mView是用于AlertDialog的视图)。setView方法)。

...
FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.**custom**);
custom.addView(**mView**, new LayoutParams(FILL_PARENT, FILL_PARENT));
...

#8


2  

The easiest way to do this is by using android.support.v7.app.AlertDialog instead of android.app.AlertDialog where public AlertDialog.Builder setView (int layoutResId) can be used below API 21.

最简单的方法是使用android.support.v7.app。AlertDialog代替android.app。AlertDialog公共AlertDialog的地方。生成器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();

#9


1  

After changing the ID it android.R.id.custom, I needed to add the following to get the View to display:

在改变ID之后,它是android.R.id。自定义,我需要添加以下内容来显示视图:

((View) f1.getParent()).setVisibility(View.VISIBLE);

However, this caused the new View to render in a big parent view with no background, breaking the dialog box in two parts (text and buttons, with the new View in between). I finally got the effect that I wanted by inserting my View next to the message:

但是,这导致新视图在没有背景的大父视图中呈现,将对话框分成两部分(文本和按钮,中间有新视图)。我终于得到了我想要的效果,在消息旁边插入我的视图:

LinearLayout f1 = (LinearLayout)findViewById(android.R.id.message).getParent().getParent();

I found this solution by exploring the View tree with View.getParent() and View.getChildAt(int). Not really happy about either, though. None of this is in the Android docs and if they ever change the structure of the AlertDialog, this might break.

我通过使用View. getparent()和View. getchildat (int)探索视图树找到了这个解决方案。不过,这两件事我都不太满意。这些都不在Android文档中,如果他们改变了AlertDialog的结构,这可能会失败。

#10


0  

Custom AlertDialog

This full example includes passing data back to the Activity.

这个完整的示例包括向活动传递数据。

如何实现自定义AlertDialog视图

Create a custom layout

A layout with an EditText is used for this simple example, but you can replace it with anything you like.

这个简单的示例使用了一个带有EditText的布局,但是您可以用您喜欢的任何东西替换它。

custom_layout.xml

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>

Use the dialog in code

The key parts are

的关键部分

  • using setView to assign the custom layout to the AlertDialog.Builder
  • 使用setView将自定义布局分配给AlertDialog.Builder
  • sending any data back to the activity when a dialog button is clicked.
  • 当单击对话框按钮时,将任何数据发送回活动。

This is the full code from the example project shown in the image above:

这是上面图片所示的示例项目的完整代码:

MainActivity.java

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

Notes

  • If you find yourself using this in multiple places, then consider making a DialogFragment subclass as is described in the documentation.
  • 如果您发现自己在多个地方都在使用它,那么请考虑按照文档中描述的那样创建一个DialogFragment子类。

See also

#11


0  

It would make the most sense to do it this way, least amount of code.

这样做最有意义,最少的代码量。

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

For an expanded list of things you can set, start typing .set in Android Studio

要查看可设置的扩展列表,请在Android Studio中输入.set