对话框

尝试 Compose 方式
Jetpack Compose 是 Android 推荐的界面工具包。了解如何在 Compose 中添加组件。

对话框 (dialog) 是一个小窗口,用于提示用户做出决定或输入额外信息。对话框不会填满屏幕,通常用于要求用户在继续操作之前执行某项操作的模式事件。

An image showing a basic dialog
图 1. 基本对话框。

Dialog 类是对话框的基类,但请勿直接实例化 Dialog。请改用以下子类之一

AlertDialog
可显示标题、最多三个按钮、可选项目列表或自定义布局的对话框。
DatePickerDialogTimePickerDialog
具有预定义界面,允许用户选择日期或时间的对话框。

这些类定义了对话框的样式和结构。您还需要一个 DialogFragment 作为对话框的容器。DialogFragment 类提供了创建对话框和管理其外观所需的所有控件,而无需直接调用 Dialog 对象上的方法。

使用 DialogFragment 管理对话框可以使其正确处理生命周期事件,例如用户轻触“返回”按钮或旋转屏幕时。DialogFragment 类还允许您将对话框界面作为可嵌入组件在更大的界面中重复使用,就像传统的 Fragment 一样,例如当您希望对话框界面在大屏和小屏设备上显示不同时。

本文档的以下部分介绍了如何结合使用 DialogFragmentAlertDialog 对象。如果您想创建日期或时间选择器,请阅读向您的应用添加选择器

创建对话框片段

您可以通过扩展 DialogFragment 并在 onCreateDialog() 回调方法中创建 AlertDialog 来实现各种对话框设计,包括自定义布局以及Material Design Dialogs 中描述的设计。

例如,以下是在 DialogFragment 中管理的基本 AlertDialog

Kotlin

class StartGameDialogFragment : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            // Use the Builder class for convenient dialog construction.
            val builder = AlertDialog.Builder(it)
            builder.setMessage("Start game")
                .setPositiveButton("Start") { dialog, id ->
                    // START THE GAME!
                }
                .setNegativeButton("Cancel") { dialog, id ->
                    // User cancelled the dialog.
                }
            // Create the AlertDialog object and return it.
            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

class OldXmlActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_old_xml)

        StartGameDialogFragment().show(supportFragmentManager, "GAME_DIALOG")
    }
}

Java

public class StartGameDialogFragment extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the Builder class for convenient dialog construction.
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.dialog_start_game)
               .setPositiveButton(R.string.start, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // START THE GAME!
                   }
               })
               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // User cancels the dialog.
                   }
               });
        // Create the AlertDialog object and return it.
        return builder.create();
    }
}
// ...

StartGameDialogFragment().show(supportFragmentManager, "GAME_DIALOG");

当您创建此类的一个实例并对该对象调用 show() 时,对话框会显示,如下图所示。

An image showing a basic dialog with two action buttons
图 2. 带有消息和两个操作按钮的对话框。

下一节提供了有关使用 AlertDialog.Builder API 创建对话框的更多详细信息。

根据对话框的复杂程度,您可以在 DialogFragment 中实现多种其他回调方法,包括所有基本的片段生命周期方法

构建警告对话框

AlertDialog 类允许您构建各种对话框设计,并且通常是您唯一需要的对话框类。如下图所示,警告对话框有三个区域

  • 标题:这是可选的,仅在内容区域被详细消息、列表或自定义布局占据时使用。如果您只需要陈述简单的消息或问题,则不需要标题。
  • 内容区域:此处可以显示消息、列表或其他自定义布局。
  • 操作按钮:对话框中最多可以有三个操作按钮。

AlertDialog.Builder 类提供的 API 允许您创建包含这些类型内容的 AlertDialog,包括自定义布局。

要构建 AlertDialog,请执行以下操作

Kotlin

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setMessage("I am the message")
    .setTitle("I am the title")

val dialog: AlertDialog = builder.create()
dialog.show()

Java

// 1. Instantiate an AlertDialog.Builder with its constructor.
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

// 2. Chain together various setter methods to set the dialog characteristics.
builder.setMessage(R.string.dialog_message)
       .setTitle(R.string.dialog_title);

// 3. Get the AlertDialog.
AlertDialog dialog = builder.create();

上一个代码片段生成此对话框

An image showing a dialog with title, content area and two action buttons.
图 3. 基本警告对话框的布局。

添加按钮

要添加如图 2 所示的操作按钮,请调用 setPositiveButton()setNegativeButton() 方法

Kotlin

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setMessage("I am the message")
    .setTitle("I am the title")
    .setPositiveButton("Positive") { dialog, which ->
        // Do something.
    }
    .setNegativeButton("Negative") { dialog, which ->
        // Do something else.
    }

val dialog: AlertDialog = builder.create()
dialog.show()

Java

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Add the buttons.
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // User taps OK button.
           }
       });
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               // User cancels the dialog.
           }
       });
// Set other dialog properties.
...

// Create the AlertDialog.
AlertDialog dialog = builder.create();

set...Button() 方法需要按钮的标题(由字符串资源提供)和定义用户轻触按钮时执行的操作的 DialogInterface.OnClickListener

您可以添加三种操作按钮

  • Positive(肯定):使用此按钮接受并继续操作(即“确定”操作)。
  • Negative(否定):使用此按钮取消操作。
  • Neutral(中性):当用户可能不想继续操作,但也不一定想取消时,请使用此按钮。它显示在肯定和否定按钮之间。例如,操作可能是“稍后提醒我”。

您只能向 AlertDialog 添加每种按钮类型的一个按钮。例如,您不能拥有多个“positive”按钮。

上一个代码片段会显示一个警告对话框,如下所示

An image showing an alert dialog with title, message, and two action buttons.
图 4. 带有标题、消息和两个操作按钮的警告对话框。

添加列表

AlertDialog API 提供三种类型的列表

  • 传统的单选列表。
  • 永久性单选列表(单选按钮)。
  • 永久性多选列表(复选框)。

要创建如图 5 所示的单选列表,请使用 setItems() 方法


Kotlin

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setTitle("I am the title")
    .setPositiveButton("Positive") { dialog, which ->
        // Do something.
    }
    .setNegativeButton("Negative") { dialog, which ->
        // Do something else.
    }
    .setItems(arrayOf("Item One", "Item Two", "Item Three")) { dialog, which ->
        // Do something on item tapped.
    }

val dialog: AlertDialog = builder.create()
dialog.show()

Java

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setTitle(R.string.pick_color)
           .setItems(R.array.colors_array, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int which) {
               // The 'which' argument contains the index position of the selected item.
           }
    });
    return builder.create();
}

此代码片段会生成一个对话框,如下所示

An image showing a dialog with a title and list.
图 5. 带有标题和列表的对话框。

由于列表显示在对话框的内容区域中,因此对话框不能同时显示消息和列表。使用 setTitle() 为对话框设置标题。要指定列表中的项目,请调用 setItems() 并传入一个数组。此外,您还可以使用 setAdapter() 来指定列表。这使您可以使用 ListAdapter 通过动态数据(例如数据库中的数据)支持列表。

如果您使用 ListAdapter 支持列表,请务必使用 Loader,以便内容异步加载。此内容在使用适配器构建布局加载器中有进一步介绍。

添加永久性多选或单选列表

要添加多选项目(复选框)列表或单选项目(单选按钮)列表,请分别使用 setMultiChoiceItems()setSingleChoiceItems() 方法。

例如,您可以按以下方式创建如图 6 所示的多选列表,并将选定的项目保存在 ArrayList

Kotlin

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setTitle("I am the title")
    .setPositiveButton("Positive") { dialog, which ->
        // Do something.
    }
    .setNegativeButton("Negative") { dialog, which ->
        // Do something else.
    }
    .setMultiChoiceItems(
        arrayOf("Item One", "Item Two", "Item Three"), null) { dialog, which, isChecked ->
        // Do something.
    }

val dialog: AlertDialog = builder.create()
dialog.show()

Java

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    selectedItems = new ArrayList();  // Where we track the selected items
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // Set the dialog title.
    builder.setTitle(R.string.pick_toppings)
    // Specify the list array, the items to be selected by default (null for
    // none), and the listener through which to receive callbacks when items
    // are selected.
           .setMultiChoiceItems(R.array.toppings, null,
                      new DialogInterface.OnMultiChoiceClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int which,
                       boolean isChecked) {
                   if (isChecked) {
                       // If the user checks the item, add it to the selected
                       // items.
                       selectedItems.add(which);
                   } else if (selectedItems.contains(which)) {
                       // If the item is already in the array, remove it.
                       selectedItems.remove(which);
                   }
               }
           })
    // Set the action buttons
           .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   // User taps OK, so save the selectedItems results
                   // somewhere or return them to the component that opens the
                   // dialog.
                   ...
               }
           })
           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   ...
               }
           });

    return builder.create();
}
An image showing a dialog containing a list of multiple-choice items.
图 6. 多选项目列表。

单选警告对话框可按如下方式获得

Kotlin

val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
    .setTitle("I am the title")
    .setPositiveButton("Positive") { dialog, which ->
        // Do something.
    }
    .setNegativeButton("Negative") { dialog, which ->
        // Do something else.
    }
    .setSingleChoiceItems(
        arrayOf("Item One", "Item Two", "Item Three"), 0
    ) { dialog, which ->
        // Do something.
    }

val dialog: AlertDialog = builder.create()
dialog.show()

Java

        String[] choices = {"Item One", "Item Two", "Item Three"};
        
        AlertDialog.Builder builder = AlertDialog.Builder(context);
        builder
                .setTitle("I am the title")
                .setPositiveButton("Positive", (dialog, which) -> {

                })
                .setNegativeButton("Negative", (dialog, which) -> {

                })
                .setSingleChoiceItems(choices, 0, (dialog, which) -> {

                });

        AlertDialog dialog = builder.create();
        dialog.show();

结果如下例所示

An image showing a dialog containing a list of single-choice items.
图 7. 单选项目列表。

创建自定义布局

如果您想在对话框中使用自定义布局,请创建布局并通过对 AlertDialog.Builder 对象调用 setView() 将其添加到 AlertDialog

An image showing a custom dialog layout.
图 8. 自定义对话框布局。

默认情况下,自定义布局会填满对话框窗口,但您仍然可以使用 AlertDialog.Builder 方法添加按钮和标题。

例如,以下是前面自定义对话框布局的布局文件

res/layout/dialog_signin.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ImageView
        android:src="@drawable/header_logo"
        android:layout_width="match_parent"
        android:layout_height="64dp"
        android:scaleType="center"
        android:background="#FFFFBB33"
        android:contentDescription="@string/app_name" />
    <EditText
        android:id="@+id/username"
        android:inputType="textEmailAddress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginBottom="4dp"
        android:hint="@string/username" />
    <EditText
        android:id="@+id/password"
        android:inputType="textPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginBottom="16dp"
        android:fontFamily="sans-serif"
        android:hint="@string/password"/>
</LinearLayout>

要在 DialogFragment 中膨胀布局,请使用 getLayoutInflater() 获取 LayoutInflater 并调用 inflate()。第一个参数是布局资源 ID,第二个参数是布局的父视图。然后,您可以调用 setView() 将布局放置在对话框中。示例如下。

Kotlin

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return activity?.let {
        val builder = AlertDialog.Builder(it)
        // Get the layout inflater.
        val inflater = requireActivity().layoutInflater;

        // Inflate and set the layout for the dialog.
        // Pass null as the parent view because it's going in the dialog
        // layout.
        builder.setView(inflater.inflate(R.layout.dialog_signin, null))
                // Add action buttons.
                .setPositiveButton(R.string.signin,
                        DialogInterface.OnClickListener { dialog, id ->
                            // Sign in the user.
                        })
                .setNegativeButton(R.string.cancel,
                        DialogInterface.OnClickListener { dialog, id ->
                            getDialog().cancel()
                        })
        builder.create()
    } ?: throw IllegalStateException("Activity cannot be null")
}

Java

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // Get the layout inflater.
    LayoutInflater inflater = requireActivity().getLayoutInflater();

    // Inflate and set the layout for the dialog.
    // Pass null as the parent view because it's going in the dialog layout.
    builder.setView(inflater.inflate(R.layout.dialog_signin, null))
    // Add action buttons
           .setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int id) {
                   // Sign in the user.
               }
           })
           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   LoginDialogFragment.this.getDialog().cancel();
               }
           });
    return builder.create();
}

如果您想要自定义对话框,可以代わりに将 Activity 作为对话框显示,而不是使用 Dialog API。创建一个 Activity,并在 <activity> 清单元素中将其主题设置为 Theme.Holo.Dialog

<activity android:theme="@android:style/Theme.Holo.Dialog" >

现在 Activity 会显示在对话框窗口中,而不是全屏显示。

将事件传回对话框的宿主

当用户轻触对话框的操作按钮之一或从其列表中选择项目时,您的 DialogFragment 可能会自行执行必要的操作,但通常您希望将事件传递给打开对话框的 activity 或 fragment。为此,请定义一个包含每种点击事件方法 的接口。然后,在接收对话框的操作事件的宿主组件中实现该接口。

例如,以下是一个 DialogFragment,它定义了一个接口,通过该接口将事件传回宿主 Activity

Kotlin

class NoticeDialogFragment : DialogFragment() {
    // Use this instance of the interface to deliver action events.
    internal lateinit var listener: NoticeDialogListener

    // The activity that creates an instance of this dialog fragment must
    // implement this interface to receive event callbacks. Each method passes
    // the DialogFragment in case the host needs to query it.
    interface NoticeDialogListener {
        fun onDialogPositiveClick(dialog: DialogFragment)
        fun onDialogNegativeClick(dialog: DialogFragment)
    }

    // Override the Fragment.onAttach() method to instantiate the
    // NoticeDialogListener.
    override fun onAttach(context: Context) {
        super.onAttach(context)
        // Verify that the host activity implements the callback interface.
        try {
            // Instantiate the NoticeDialogListener so you can send events to
            // the host.
            listener = context as NoticeDialogListener
        } catch (e: ClassCastException) {
            // The activity doesn't implement the interface. Throw exception.
            throw ClassCastException((context.toString() +
                    " must implement NoticeDialogListener"))
        }
    }
}

Java

public class NoticeDialogFragment extends DialogFragment {

    // The activity that creates an instance of this dialog fragment must
    // implement this interface to receive event callbacks. Each method passes
    // the DialogFragment in case the host needs to query it.
    public interface NoticeDialogListener {
        public void onDialogPositiveClick(DialogFragment dialog);
        public void onDialogNegativeClick(DialogFragment dialog);
    }

    // Use this instance of the interface to deliver action events.
    NoticeDialogListener listener;

    // Override the Fragment.onAttach() method to instantiate the
    // NoticeDialogListener.
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        // Verify that the host activity implements the callback interface.
        try {
            // Instantiate the NoticeDialogListener so you can send events to
            // the host.
            listener = (NoticeDialogListener) context;
        } catch (ClassCastException e) {
            // The activity doesn't implement the interface. Throw exception.
            throw new ClassCastException(activity.toString()
                    + " must implement NoticeDialogListener");
        }
    }
    ...
}

宿主 Activity 使用对话框片段的构造函数创建对话框实例,并通过实现 NoticeDialogListener 接口接收对话框的事件

Kotlin

class MainActivity : FragmentActivity(),
        NoticeDialogFragment.NoticeDialogListener {

    fun showNoticeDialog() {
        // Create an instance of the dialog fragment and show it.
        val dialog = NoticeDialogFragment()
        dialog.show(supportFragmentManager, "NoticeDialogFragment")
    }

    // The dialog fragment receives a reference to this Activity through the
    // Fragment.onAttach() callback, which it uses to call the following
    // methods defined by the NoticeDialogFragment.NoticeDialogListener
    // interface.
    override fun onDialogPositiveClick(dialog: DialogFragment) {
        // User taps the dialog's positive button.
    }

    override fun onDialogNegativeClick(dialog: DialogFragment) {
        // User taps the dialog's negative button.
    }
}

Java

public class MainActivity extends FragmentActivity
                          implements NoticeDialogFragment.NoticeDialogListener{
    ...
    public void showNoticeDialog() {
        // Create an instance of the dialog fragment and show it.
        DialogFragment dialog = new NoticeDialogFragment();
        dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
    }

    // The dialog fragment receives a reference to this Activity through the
    // Fragment.onAttach() callback, which it uses to call the following
    // methods defined by the NoticeDialogFragment.NoticeDialogListener
    // interface.
    @Override
    public void onDialogPositiveClick(DialogFragment dialog) {
        // User taps the dialog's positive button.
        ...
    }

    @Override
    public void onDialogNegativeClick(DialogFragment dialog) {
        // User taps the dialog's negative button.
        ...
    }
}

由于宿主 Activity 实现了 NoticeDialogListener(上例中所示的 onAttach() 回调方法强制要求),对话框片段可以使用接口回调方法向 Activity 传递点击事件

Kotlin

    override fun onCreateDialog(savedInstanceState: Bundle): Dialog {
        return activity?.let {
            // Build the dialog and set up the button click handlers.
            val builder = AlertDialog.Builder(it)

            builder.setMessage(R.string.dialog_start_game)
                    .setPositiveButton(R.string.start,
                            DialogInterface.OnClickListener { dialog, id ->
                                // Send the positive button event back to the
                                // host activity.
                                listener.onDialogPositiveClick(this)
                            })
                    .setNegativeButton(R.string.cancel,
                            DialogInterface.OnClickListener { dialog, id ->
                                // Send the negative button event back to the
                                // host activity.
                                listener.onDialogNegativeClick(this)
                            })

            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }

Java

public class NoticeDialogFragment extends DialogFragment {
    ...
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Build the dialog and set up the button click handlers.
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setMessage(R.string.dialog_start_game)
               .setPositiveButton(R.string.start, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // Send the positive button event back to the host activity.
                       listener.onDialogPositiveClick(NoticeDialogFragment.this);
                   }
               })
               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       // Send the negative button event back to the host activity.
                       listener.onDialogNegativeClick(NoticeDialogFragment.this);
                   }
               });
        return builder.create();
    }
}

显示对话框

当您想显示对话框时,请创建 DialogFragment 的实例,并调用 show(),传入 FragmentManager 和对话框片段的标签名。

您可以从 FragmentActivity 调用 getSupportFragmentManager() 或从 Fragment 调用 getParentFragmentManager() 获取 FragmentManager。示例如下:

Kotlin

fun confirmStartGame() {
    val newFragment = StartGameDialogFragment()
    newFragment.show(supportFragmentManager, "game")
}

Java

public void confirmStartGame() {
    DialogFragment newFragment = new StartGameDialogFragment();
    newFragment.show(getSupportFragmentManager(), "game");
}

第二个参数 "game" 是一个唯一的标签名,系统在必要时用于保存和恢复 fragment 状态。您也可以通过调用 findFragmentByTag(),利用该标签获取 fragment 的句柄。

全屏显示对话框或将其作为嵌入式片段显示

您可能希望界面的某个部分在某些情况下显示为对话框,而在其他情况下显示为全屏或嵌入式 fragment。您可能还希望它根据设备的屏幕尺寸显示不同。DialogFragment 类提供了实现此目的的灵活性,因为它可以作为可嵌入的 Fragment 行为。

但是,在这种情况下,您不能使用 AlertDialog.Builder 或其他 Dialog 对象来构建对话框。如果您希望 DialogFragment 可嵌入,请在布局中定义对话框的 UI,然后在 onCreateView() 回调中加载布局。

以下是一个 DialogFragment 示例,它可以使用名为 purchase_items.xml 的布局,以对话框或可嵌入 fragment 的形式出现

Kotlin

class CustomDialogFragment : DialogFragment() {

    // The system calls this to get the DialogFragment's layout, regardless of
    // whether it's being displayed as a dialog or an embedded fragment.
    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View {
        // Inflate the layout to use as a dialog or embedded fragment.
        return inflater.inflate(R.layout.purchase_items, container, false)
    }

    // The system calls this only when creating the layout in a dialog.
    override fun onCreateDialog(savedInstanceState: Bundle): Dialog {
        // The only reason you might override this method when using
        // onCreateView() is to modify the dialog characteristics. For example,
        // the dialog includes a title by default, but your custom layout might
        // not need it. Here, you can remove the dialog title, but you must
        // call the superclass to get the Dialog.
        val dialog = super.onCreateDialog(savedInstanceState)
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        return dialog
    }
}

Java

public class CustomDialogFragment extends DialogFragment {
    // The system calls this to get the DialogFragment's layout, regardless of
    // whether it's being displayed as a dialog or an embedded fragment.
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Inflate the layout to use as a dialog or embedded fragment.
        return inflater.inflate(R.layout.purchase_items, container, false);
    }

    // The system calls this only when creating the layout in a dialog.
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // The only reason you might override this method when using
        // onCreateView() is to modify the dialog characteristics. For example,
        // the dialog includes a title by default, but your custom layout might
        // not need it. Here, you can remove the dialog title, but you must
        // call the superclass to get the Dialog.
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        return dialog;
    }
}

以下示例根据屏幕尺寸确定是显示 fragment 为对话框还是全屏界面

Kotlin

fun showDialog() {
    val fragmentManager = supportFragmentManager
    val newFragment = CustomDialogFragment()
    if (isLargeLayout) {
        // The device is using a large layout, so show the fragment as a
        // dialog.
        newFragment.show(fragmentManager, "dialog")
    } else {
        // The device is smaller, so show the fragment fullscreen.
        val transaction = fragmentManager.beginTransaction()
        // For a polished look, specify a transition animation.
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
        // To make it fullscreen, use the 'content' root view as the container
        // for the fragment, which is always the root view for the activity.
        transaction
                .add(android.R.id.content, newFragment)
                .addToBackStack(null)
                .commit()
    }
}

Java

public void showDialog() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    CustomDialogFragment newFragment = new CustomDialogFragment();

    if (isLargeLayout) {
        // The device is using a large layout, so show the fragment as a
        // dialog.
        newFragment.show(fragmentManager, "dialog");
    } else {
        // The device is smaller, so show the fragment fullscreen.
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        // For a polished look, specify a transition animation.
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        // To make it fullscreen, use the 'content' root view as the container
        // for the fragment, which is always the root view for the activity.
        transaction.add(android.R.id.content, newFragment)
                   .addToBackStack(null).commit();
    }
}

有关执行 fragment 事务的详细信息,请参阅片段

在此示例中,布尔值 mIsLargeLayout 指定当前设备是否必须使用应用的大布局设计,并因此将此 fragment 显示为对话框而非全屏。设置此类布尔值的最佳方法是声明一个 bool 资源值,并为不同的屏幕尺寸提供备用资源值。例如,以下是 bool 资源的两个版本,适用于不同的屏幕尺寸

res/values/bools.xml

<!-- Default boolean values -->
<resources>
    <bool name="large_layout">false</bool>
</resources>

res/values-large/bools.xml

<!-- Large screen boolean values -->
<resources>
    <bool name="large_layout">true</bool>
</resources>

然后,您可以在 activity 的 onCreate() 方法期间初始化 mIsLargeLayout 值,如下例所示

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    isLargeLayout = resources.getBoolean(R.bool.large_layout)
}

Java

boolean isLargeLayout;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    isLargeLayout = getResources().getBoolean(R.bool.large_layout);
}

在大屏设备上将 Activity 显示为对话框

您无需在小屏设备上将对话框显示为全屏界面,而是在大屏设备上将 Activity 显示为对话框,即可达到同样的效果。您选择的方法取决于您的应用设计,但将 activity 显示为对话框通常适用于为小屏设备设计的应用,并且您希望通过将短期 activity 显示为对话框来改进平板电脑上的体验。

若要仅在大屏设备上将 activity 显示为对话框,请将 Theme.Holo.DialogWhenLarge 主题应用到 <activity> 清单元素

<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" >

有关使用主题设置 activity 样式的更多信息,请参阅样式和主题

关闭对话框

当用户轻触使用 AlertDialog.Builder 创建的操作按钮时,系统会自动关闭对话框。

当用户轻触对话框列表中的项目时,系统也会关闭对话框,除非列表使用单选按钮或复选框。否则,您可以对 DialogFragment 调用 dismiss() 来手动关闭对话框。

如果对话框消失时需要执行某些操作,您可以在 DialogFragment 中实现 onDismiss() 方法。

您还可以取消对话框。这是一个特殊事件,表示用户未完成任务就离开对话框。当用户轻触“返回”按钮或对话框区域外部的屏幕,或者您明确对 Dialog 调用 cancel() 时(例如,作为对话框中“取消”按钮的响应),就会发生此事件。

如上例所示,您可以在 DialogFragment 类中实现 onCancel() 来响应取消事件。