【Flutter】Dialog Tips集

# AlertDialog

[AlertDialog class - material library - Dart API](https://api.flutter.dev/flutter/material/AlertDialog-class.html)

## 画面起動直後にダイアログを表示したい

addPostFrameCallbackメソッドを利用し、画面の描画が終わったタイミングで表示させるようにする。
[addPostFrameCallback method - SchedulerBinding class - scheduler library - Dart API](https://api.flutter.dev/flutter/scheduler/SchedulerBinding/addPostFrameCallback.html)

```dart
@override
  Widget build(BuildContext context) {
    // 画面の描画が終わったタイミングで表示させる
    WidgetsBinding.instance.addPostFrameCallback((_) => showDialog(
      context: context,
      builder: (_) {
        return AlertDialog(
          title: Center(child: Text("タイトル"),),
          content: Text("ここにメッセージが表示される"),
          actions: <Widget>[
            FlatButton(
              child: Text("キャンセル"),
              onPressed: () => Navigator.pop(context),
            ),
            FlatButton(
              child: Text("OK"),
              onPressed: () => Navigator.pop(context),
            ),
          ],
        );
      },
    ));

    return Scaffold(
      // ...
    );
  }
```

## ボタンを中央寄せで表示したい

引数actionsに定義すると、どうやってもボタンが右寄せになってしまう。
そのため、ColumnやRowなどを利用して、引数contentにボタンを定義する。
その分、ダイアログ下側に余白ができてしまうため、引数contentPaddingを設定して調整する。

```dart
showDialog(
        context: context,
        builder: (_) {
          return AlertDialog(
            title: Center(child: Text("タイトル"),),
            content: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Text("ここにメッセージを書く"),
                // アクション用ボタンを定義する
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    FlatButton(
                      child: Text("キャンセル"),
                      onPressed: () => Navigator.pop(context),
                    ),
                    FlatButton(
                      child: Text("OK"),
                      onPressed: () => Navigator.pop(context),
                    ),
                  ],
                ),
              ],
            ),
            // ダイアログの余白を調整
            contentPadding: EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 8.0),
          );
        });
```

## ダイアログ上のアクションを検知させたい

例えば、チェックボックスにチェックが入っているときにだけ、ボタンが押せるようにしたいときは、
setStateメソッドを利用してアクションを検知させるようにする。
[setState method - State class - widgets library - Dart API](https://api.flutter.dev/flutter/widgets/State/setState.html)

```dart:check_box_dialog.dart
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class CheckBoxDialog extends StatefulWidget {
  CheckBoxDialog(this.title, this.message, this.checkBoxCaption,
      [this.positiveCaption,
      this.onPositive,
      this.negativeCaption,
      this.onNegative]);

  final String title;
  final String message;
  final String checkBoxCaption;
  final String positiveCaption;
  final Function onPositive;
  final String negativeCaption;
  final Function onNegative;

  @override
  CheckBoxDialogState createState() => CheckBoxDialogState();
}

class CheckBoxDialogState extends State<CheckBoxDialog> {
  bool _isChecked = false;

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Center(
        child: Text(widget.title),
      ),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text(widget.message),
          Container(
            padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
            child: CheckboxListTile(
              value: _isChecked,
              title: Text(
                widget.checkBoxCaption,
              ),
              controlAffinity: ListTileControlAffinity.leading,
              // チェックボックスを押下すると以下の処理が実行される
              onChanged: (bool value) {
                setState(() {
                  _isChecked = value;
                });
              },
            ),
          ),
          Container(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                FlatButton(
                    child: Text(widget.negativeCaption),
                    onPressed: () {
                      Navigator.pop(context);
                      if (widget.onNegative != null) {
                        widget.onNegative();
                      }
                    }),
                FlatButton(
                    child: Text(widget.positiveCaption),
                    onPressed: _isChecked
                        ? () {
                            Navigator.pop(context);
                            if (widget.onPositive != null) {
                              widget.onPositive();
                            }
                          }
                        : null),
              ],
            ),
          ),
        ],
      ),
      contentPadding: EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 10.0),
    );
  }
}
```

呼び出す際は以下のように記述する。

```dart
showDialog(
          context: context,
          builder: (_) {
            return CheckBoxDialog(
                "タイトル",
                "ここにメッセージが表示される",
                "チェックを入れる",
                "OK",
                () {
                  // ここにOK時の処理を入れる
                },
                "キャンセル",
                () {
                  // ここにキャンセル時の処理を入れる
                });
          },
        ));
```

## ダイアログ表示時、ダイアログのボタンを押す以外でダイアログが閉じないようにしたい

barrierDismissibleをfalseにし、ダイアログの外をタップしても閉じないようにする。
そして、AlertDialogをWillPopScopeでラップし、OSのバックキー押下時の挙動を上書きし、閉じさせないようにする。
[showDialog function - material library - Dart API](https://api.flutter.dev/flutter/material/showDialog.html)
[WillPopScope class - widgets library - Dart API](https://api.flutter.dev/flutter/widgets/WillPopScope-class.html)

```dart
showDialog(
        context: context,
        // ダイアログの外をタップしても閉じないようにする
        barrierDismissible: false,
        builder: (_) {
          return WillPopScope(
              // 戻るボタン押下時の処理を上書き
              onWillPop: () async => false,
              child: AlertDialog(
            title: Center(child: Text("タイトル"),),
            content: Text("ここにメッセージが表示される"),
            actions: <Widget>[
              FlatButton(
                child: Text("キャンセル"),
                onPressed: () => Navigator.pop(context),
              ),
              FlatButton(
                child: Text("OK"),
                onPressed: () => Navigator.pop(context),
              ),
            ],
          ),);
        });
```