對話方塊

嘗試 Compose 方法
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中新增元件。

「對話方塊」是一個小型視窗,提示使用者做出決定或輸入其他資訊。對話方塊未填滿畫面,通常用於強制回應事件,使用者必須先執行動作才能繼續操作。

顯示基本對話方塊的圖片
圖 1.基本對話方塊。

Dialog 類別是對話方塊的基礎類別,但不會直接為 Dialog 執行個體化。請改用下列其中一個子類別:

AlertDialog
對話方塊可顯示標題、最多 3 個按鈕、可選取項目清單或自訂版面配置。
DatePickerDialogTimePickerDialog
這個對話方塊含有預先定義的 UI,可讓使用者選取日期或時間。

這些類別會定義對話方塊的樣式和結構。您還需要 DialogFragment 做為對話方塊的容器。DialogFragment 類別提供建立對話方塊及管理其外觀所需的所有控制項,而不是在 Dialog 物件上呼叫方法。

使用 DialogFragment 管理對話方塊後,即可正確處理生命週期事件,例如使用者輕觸「返回」按鈕或旋轉畫面時。DialogFragment 類別也可讓您重複使用對話方塊的 UI,做為大型 UI 中的可嵌入元件,就像傳統 Fragment 一樣,例如您希望對話方塊 UI 在大、小的螢幕上以不同的方式呈現。

本文件的以下章節說明如何搭配使用 DialogFragmentAlertDialog 物件。如要建立日期或時間挑選器,請參閱「在應用程式中新增挑選器」。

建立對話方塊片段

您可以在 onCreateDialog() 回呼方法中擴充 DialogFragment 並建立 AlertDialog,藉此完成各種對話方塊設計,包括自訂版面配置以及質感設計對話方塊中所述的作業。

例如,以下是在 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() 時,對話方塊會如下圖所示。

顯示包含兩個動作按鈕的基本對話方塊的圖片
圖 2. 顯示訊息和兩個動作按鈕的對話方塊。

下一節將詳細說明如何使用 AlertDialog.Builder API 建立對話方塊。

您可以根據對話方塊的複雜程度,您可以在 DialogFragment 中實作各種其他回呼方法,包括所有基本片段生命週期方法

建構快訊對話方塊

AlertDialog 類別可讓您建構各種對話方塊設計,而且通常是您需要的唯一對話方塊類別。如下圖所示,快訊對話方塊有三個區域:

  • 「Title」:此為選用元素,只有在內容區域佔滿詳細訊息、清單或自訂版面配置時,才能使用。如要提供簡單的訊息或問題,則不需要標題。
  • 內容區域:可顯示訊息、清單或其他自訂版面配置。
  • 動作按鈕:對話方塊中最多可有三個動作按鈕。

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

上一個程式碼片段會產生這個對話方塊:

這張圖片顯示對話方塊,其中包含標題、內容區域和兩個動作按鈕。
圖 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,以定義使用者輕觸按鈕時要採取的動作。

您可以新增下列三個動作按鈕:

  • 正向:使用此方法接受並繼續動作 (「確定」動作)。
  • 排除:使用這個選項取消動作。
  • 普通:如果使用者不想繼續執行動作,但不一定想要取消,請使用此模式。它會顯示在正面和負面按鈕之間。舉例來說,這項操作可能會是「稍後提醒我」。

每個按鈕類型只能有一個按鈕新增至 AlertDialog。例如,只能有一個「正面」按鈕。

上述程式碼片段顯示快訊對話方塊,如下所示:

顯示快訊對話方塊的圖片,其中含有標題、訊息和兩個動作按鈕。
圖 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();
}

這個程式碼片段會產生類似下方的對話方塊:

顯示含有標題和清單的對話方塊的圖片。
圖 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();
}
顯示含有選擇題清單的對話方塊的圖片。
圖 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();

這會產生以下示例:

顯示含有單選項目清單的對話方塊的圖片。
圖 7.單選項目清單。

建立自訂版面配置

如果您希望在對話方塊中使用自訂版面配置,請建立版面配置,並在 AlertDialog.Builder 物件上呼叫 setView(),將其新增至 AlertDialog

顯示自訂對話方塊版面配置的圖片。
圖 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> 資訊清單元素中將主題設為 Theme.Holo.Dialog

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

活動現在會在對話方塊 (而非全螢幕) 中顯示。

將事件傳回對話方塊的主機

當使用者輕觸對話方塊的動作按鈕,或從清單中選取項目時,DialogFragment 可能會執行必要的動作,但通常會您希望將事件傳遞到開啟對話方塊的活動或片段。如要這麼做,請定義每個類型點擊事件類型的介面。然後在主機元件中實作該介面,以便接收來自對話方塊的動作事件。

舉例來說,以下 DialogFragment 定義了一個介面,該介面可透過該介面將事件傳遞回代管活動:

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");
        }
    }
    ...
}

代管對話方塊的活動會建立含有對話方塊片段建構函式的對話方塊執行個體,並透過實作 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.
        ...
    }
}

由於代管活動會實作 NoticeDialogListener (由上述範例中顯示的 onAttach() 回呼方法強制執行),因此對話方塊片段可以使用介面回呼方法,將點擊事件傳送至活動:

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" 是不重複的標記名稱,可供系統視需要儲存及還原片段狀態。標記還可讓您呼叫 findFragmentByTag(),取得片段的控制代碼。

以全螢幕或嵌入片段的形式顯示對話方塊

您可能希望 UI 設計在某些情況下顯示為對話方塊,而在其他情況下則以全螢幕或嵌入片段的形式顯示。您可能也會希望應用程式在裝置的螢幕大小以不同方式呈現。DialogFragment 類別提供以嵌入式 Fragment 的方式執行此操作,因此提供靈活的運用方式。

不過,在這種情況下,您無法使用 AlertDialog.Builder 或其他 Dialog 物件建構對話方塊。如果您希望嵌入 DialogFragment,請在版面配置中定義對話方塊的 UI,然後在 onCreateView() 回呼中載入版面配置。

以下 DialogFragment 範例可能會顯示為對話方塊或可嵌入的片段,並使用名為 purchase_items.xml 的版面配置:

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

以下範例會根據螢幕大小,決定是否要將片段顯示為對話方塊或全螢幕 UI:

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

如要進一步瞭解如何執行片段交易,請參閱「片段」一文。

在這個範例中,mIsLargeLayout 布林值指定目前的裝置是否必須使用應用程式的大型版面配置設計,因此會將這個片段顯示為對話方塊,而非全螢幕。設定這類布林值的最佳方式,是針對不同的螢幕大小宣告具有替代資源值的 布爾資源值。例如,以下是針對不同螢幕大小的布爾資源的兩個版本:

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>

接著,您可以在活動的 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);
}

在大螢幕上顯示活動對話方塊

除了在小螢幕上將對話方塊顯示為全螢幕 UI,只要在大螢幕上將 Activity 顯示為對話方塊,就可以取得相同的結果。您選擇的方法取決於應用程式設計,但如果應用程式是專為小螢幕設計,而您希望藉由顯示短期活動做為對話方塊改善平板電腦體驗,建議將活動顯示為對話方塊是很實用的做法。

如果只想在大螢幕上將活動顯示為對話方塊,請將 Theme.Holo.DialogWhenLarge 主題套用至 <activity> 資訊清單元素:

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

如要進一步瞭解如何透過主題設定活動樣式,請參閱「樣式和主題」。

關閉對話方塊

當使用者輕觸使用 AlertDialog.Builder 建立的動作按鈕時,系統會為您關閉對話方塊。

使用者輕觸對話方塊中的項目時,系統也會關閉對話方塊,除非該清單使用圓形按鈕或核取方塊。或者,您可以在 DialogFragment 上呼叫 dismiss() 來手動關閉對話方塊。

如果您需要在對話方塊關閉時執行特定動作,可以在 DialogFragment 中實作 onDismiss() 方法。

你也可以「Cancel」對話方塊。這個特殊事件表示使用者在未完成工作時就離開對話方塊。如果使用者輕觸返回按鈕或輕觸對話方塊區域外的畫面,或是您明確呼叫 Dialog 上的 cancel(),就會發生這種情形,例如回應對話方塊中的「Cancel」按鈕。

如上述範例所示,您可以在 DialogFragment 類別中實作 onCancel(),藉此回應取消事件。