ダイアログ

Compose を試す
Jetpack Compose は Android の推奨 UI ツールキットです。Compose でコンポーネントを追加する方法を学習します。

ダイアログは、ユーザーに意思決定や追加情報の入力を求める小さなウィンドウです。ダイアログは画面全体に表示されるのではなく、通常は、続行する前にユーザーに操作を求めるモーダル イベントに使用されます。

基本的なダイアログを示す画像
図 1.基本的なダイアログ

Dialog クラスはダイアログの基本クラスですが、Dialog は直接インスタンス化しません。代わりに、次のいずれかのサブクラスを使用します。

AlertDialog
タイトル、最大 3 つのボタン、選択可能なアイテムのリスト、カスタム レイアウトを表示できるダイアログ。
DatePickerDialog または TimePickerDialog
ユーザーが日付や時刻を選択できる事前定義された UI を含むダイアログ。

これらのクラスは、ダイアログのスタイルと構造を定義します。また、ダイアログのコンテナとして DialogFragment も必要です。DialogFragment クラスは、Dialog オブジェクトでメソッドを呼び出す代わりに、ダイアログの作成と外観の管理に必要なすべてのコントロールを提供します。

DialogFragment を使用してダイアログを管理すると、ユーザーによる [戻る] ボタンのタップや画面の回転など、ライフサイクル イベントを正しく処理できるようになります。また、DialogFragment クラスを使用すると、従来の Fragment と同様に、ダイアログの UI を大小の画面で異なるように表示する場合など、大きな UI の埋め込み可能なコンポーネントとしてダイアログの UI を再利用できます。

このドキュメントの以降のセクションでは、DialogFragmentAlertDialog オブジェクトと組み合わせて使用する方法について説明します。日付または時刻の選択ツールを作成する場合は、アプリに選択ツールを追加するをご覧ください。

ダイアログ フラグメントを作成する

DialogFragment を拡張し、onCreateDialog() コールバック メソッドで 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 つの操作ボタンがある基本ダイアログの画像
図 2. メッセージと 2 つのアクション ボタンを含むダイアログ。

次のセクションでは、AlertDialog.Builder API を使用してダイアログを作成する方法について詳しく説明します。

ダイアログの複雑さに応じて、基本的なフラグメント ライフサイクル メソッドなど、他のさまざまなコールバック メソッドを DialogFragment に実装できます。

アラート ダイアログを作成する

AlertDialog クラスを使用すると、さまざまなダイアログ デザインを作成できます。多くの場合、必要なのはこのクラスのみです。次の図に示すように、アラート ダイアログには 3 つの領域があります。

  • Title: これはオプションです。コンテンツ領域が詳細メッセージ、リスト、またはカスタム レイアウトによって占有されている場合にのみ使用されます。単純なメッセージや質問を文章にする場合、タイトルは不要です。
  • コンテンツ領域: メッセージ、リスト、その他のカスタム レイアウトを表示できます。
  • アクション ボタン: ダイアログには最大 3 つのアクション ボタンを配置できます。

AlertDialog.Builder クラスには、カスタム レイアウトなどのこの種のコンテンツで AlertDialog を作成できる API が用意されています。

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

上記のコード スニペットでは、このダイアログが生成されます。

タイトル、コンテンツ領域、2 つのアクション ボタンを含むダイアログを示す画像。
図 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 が必要です。

追加できるアクション ボタンは次の 3 つです。

  • ポジティブ: これを使用してアクションを承認し、アクションを続行します(「OK」アクション)。
  • Negative: アクションをキャンセルする場合に使用します。
  • Neutral(ニュートラル): ユーザーが操作を続行したくないが、必ずしもキャンセルしたいわけではない場合に使用します。ポジティブ ボタンとネガティブ ボタンの間に表示されます。たとえば、アクションを「後で通知」にします。

AlertDialog に追加できるボタンは各タイプごとに 1 つだけです。たとえば、「ポジティブ」ボタンを複数用意することはできません。

上のコード スニペットでは、次のようなアラート ダイアログが表示されます。

タイトル、メッセージ、2 つのアクション ボタンを含むアラート ダイアログの画像。
図 4. タイトル、メッセージ、2 つのアクション ボタンを含むアラート ダイアログ。

リストを追加

AlertDialog API で使用できるリストには次の 3 種類があります。

  • 従来の単一選択リスト。
  • 永続的な選択リスト(ラジオボタン)。
  • 永続的な選択リスト(チェックボックス)。

図 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() を呼び出します。1 つ目のパラメータはレイアウト リソース ID で、2 つ目のパラメータはレイアウトの親ビューです。その後、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();
}

カスタム ダイアログが必要な場合は、Dialog API を使用する代わりに、Activity をダイアログとして表示できます。アクティビティを作成し、<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 とタグ名を渡します。

FragmentManager を取得するには、FragmentActivity から getSupportFragmentManager() を呼び出すか、Fragment から getParentFragmentManager() を呼び出します。次の例をご覧ください。

Kotlin

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

Java

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

2 番目の引数 "game" は、必要に応じてフラグメントの状態を保存および復元するためにシステムが使用する一意のタグ名です。また、このタグを使用すると、findFragmentByTag() を呼び出してフラグメントに対するハンドルを取得することもできます。

ダイアログを全画面表示または埋め込みフラグメントとして表示する

状況によっては UI デザインの一部をダイアログとして表示したり、全画面フラグメントや埋め込みフラグメントとして表示したい場合があるかもしれません。デバイスの画面サイズに応じて表示を変えることもできます。DialogFragment クラスは埋め込み可能な Fragment として動作できるため、これを簡単に実現できます。

ただし、この場合、AlertDialog.Builder または他の Dialog オブジェクトを使用してダイアログを作成することはできません。DialogFragment を埋め込む場合は、レイアウトでダイアログの UI を定義してから、onCreateView() コールバックでレイアウトを読み込みます。

purchase_items.xml というレイアウトを使用して、ダイアログまたは埋め込み可能なフラグメントとして表示できる DialogFragment の例を次に示します。

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 ブール値を使って、現在のデバイスでアプリの大きなレイアウト デザインを使用する必要がある(つまり、このフラグメントを全画面ではなくダイアログとして表示する必要がある)かどうかを指定します。このようなブール値を設定する最善の方法は、さまざまな画面サイズに対して代替リソース値を使用して、ブール値リソース値を宣言することです。例として、異なる画面サイズのブールリソースを 2 種類示します。

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 で作成したアクション ボタンをユーザーがタップすると、ダイアログが閉じます。

また、ユーザーがダイアログ リスト内のアイテムをタップすると、ダイアログが閉じられます(リストでラジオボタンまたはチェックボックスが使用されている場合を除きます)。それ以外の場合は、DialogFragmentdismiss() を呼び出して、ダイアログを手動で閉じることができます。

ダイアログが閉じられたときに特定のアクションを実行する必要がある場合は、onDismiss() メソッドを DialogFragment に実装できます。

ダイアログをキャンセルすることもできます。これは、ユーザーがタスクを完了せずにダイアログを閉じたことを示す特別なイベントです。これは、ユーザーが [戻る] ボタンをタップするか、ダイアログ領域の外側で画面をタップした場合、またはダイアログの [キャンセル] ボタンに対する応答などで、デベロッパーが Dialog で明示的に cancel() を呼び出した場合に発生します。

上記の例に示すように、DialogFragment クラスに onCancel() を実装することで、キャンセル イベントに対応できます。