【Flutter/Dart】アラートダイアログやモーダルの実装方法!showDialog

【Flutter/Dart】アラートダイアログやモーダルの実装方法!showDialog

この記事からわかること

  • Flutter/Dartアラートダイアログモーダル実装方法
  • showModalBottomSheetshowDialogAlertDialog Widget使い方

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

Flutterでアラートダイアログやモーダルの実装方法

Flutterで「ボタンを押下した後の結果表示するアラートダイアログ」や「入力画面や編集画面を表示するモーダル画面」の実装方法をまとめていきます。またFlutterではAndroidライクなマテリアルデザインiOSライクなクパチーノデザインが存在し、アラートダイアログでも存在するので使い分けて開発することが可能です。

アラート(マテリアルデザイン)

【Flutter/Dart】アラートダイアログやモーダルの実装方法!showDialog

アラート(クパチーノデザイン)

【Flutter/Dart】アラートダイアログやモーダルの実装方法!showDialog

モーダル

【Flutter/Dart】アラートダイアログやモーダルの実装方法!showDialog

※ モーダルもマテリアルとクパチーノが用意されていますが、UIに大きく変化はありません。

マテリアルデザインのアラートダイアログの実装方法

マテリアルデザインのアラートダイアログを表示させるにはshowDialogメソッドを使用します。これを使用することで画面の中央にポップアップ表示させることが可能になります。ダイアログに表示させたい内容はAlertDialogを使用します。titlecontentactionsからそれぞれ指定が可能で、actionsの中にボタン Widgetを渡すことで任意の処理を実行することが可能です。

ダイアログを明示的に閉じたい場合はNavigator.of(context).pop()を使用します。

void showMyDialog(BuildContext context) {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text("確認"),
        content: Text("この操作を実行しますか?"),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text("キャンセル"),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.of(context).pop();
            },
            child: Text("OK"),
          ),
        ],
      );
    },
  );
}
【Flutter/Dart】アラートダイアログやモーダルの実装方法!showDialog

周りをタップで閉じないようにする

デフォルトではダイアログの周りをタップするとダイアログが非表示になりますが、これを非表示にしたくない場合はbarrierDismissiblefalseを指定すればOKです。

showDialog(
    context: context,
    barrierDismissible: false, // ダイアログの周りをタップで閉じなくなる
    builder: (BuildContext context) {
      // UI
    }
)

クパチーノデザインのアラートダイアログの実装方法

クパチーノデザインのアラートダイアログを表示させるにはshowCupertinoDialogメソッドを使用します。基本的な使い方はshowDialogと変わりません。

void _showConfirmAlert(BuildContext context) {
  showCupertinoDialog(
    context: context,
    builder: (BuildContext context) {
      return CupertinoAlertDialog(
        title: Text("確認"),
        content: Text("この操作を実行しますか?"),
        actions: [
          TextButton(
              onPressed: () => Navigator.of(context).pop(),
            child: Text("キャンセル"),
          ),
          TextButton(
            onPressed: () {
              Navigator.of(context).pop();
            },
            child: Text("OK"),
          ),
        ],
      );
    },
  );
}
【Flutter/Dart】アラートダイアログやモーダルの実装方法!showDialog

またクパチーノデザインのアラートダイアログでは特に設定をしなくてもダイアログの周りをタップしても非表示にならないようです。

マテリアルデザインのモーダルの実装方法

マテリアルデザインのモーダル画面を表示させるにはshowModalBottomSheetメソッドを使用します。これを使用することで画面の下部からシートがスライドして表示されるようになります。モーダル画面のサイズはUIのサイズに影響します。なのでMediaQueryを使用して画面自体のサイズを取得しておくと綺麗にモーダル表示できます。

ただ高さのサイズを一定以上に指定するにはisScrollControlledtrueにしておく必要があります。

void showModalView(BuildContext context) {
  showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    builder: (BuildContext context) {
      return Container(
        padding: EdgeInsets.all(16),
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height * 0.9,
        child: Column(
          children: [
            Spacer(),
            Text("モーダル画面", style: TextStyle(fontSize: 20)),
            Spacer(),
            ElevatedButton(
              onPressed: () => Navigator.pop(context),
              child: Text("閉じる"),
            ),
            Spacer(),
          ],
        ),
      );
    },
  );
}
【Flutter/Dart】アラートダイアログやモーダルの実装方法!showDialog

クパチーノデザインのモーダルの実装方法

クパチーノデザインのモーダル画面を表示させるにはshowCupertinoModalPopupメソッドを使用します。基本的な使い方はshowModalBottomSheetと変わりません。ただ角丸や背景色は明示的にBoxDecorationで指定しないと期待通りになりませんでした。

void _showModalView(BuildContext context) {
  showCupertinoModalPopup(
    context: context,
    builder: (BuildContext context) {
      return Container(
        padding: EdgeInsets.all(16),
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height * 0.9,
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.vertical(
            top: Radius.circular(20),
          ),
        ),
        child: Column(
          children: [
            Spacer(),
            Text("モーダル画面", style: TextStyle(fontSize: 20)),
            Spacer(),
            ElevatedButton(
              onPressed: () => Navigator.pop(context),
              child: Text("閉じる"),
            ),
            Spacer(),
          ],
        ),
      );
    },
  );
}

モーダルが表示されないエラーの原因と解消

showModalBottomSheetshowCupertinoModalPopupを使用しているのにモーダルが表示されないことがあります。この場合は以下のようなエラーが出ていることが多いです。

Another exception was thrown: No MaterialLocalizations found.

上記のエラーは「マテリアルローカリゼーションが見つからない」というエラーです。これは実装しているアプリのマテリアル/クパチーノテーマの構造に問題がある可能性があります。アプリのルートでMaterialApp/CupertinoAppを指定すると思いますが、これが使用するモーダルと同じになっているか確認してみてください。他にもScaffold/CupertinoPageScaffoldMaterialPageRoute/CupertinoPageRouteなども統一しておくと安心です。

void main() {
  // MaterialApp => Android
  // CupertinoApp => iOS
  runApp(const CupertinoApp(home: MyCupertinoPage()));
}

class MyCupertinoPage extends StatelessWidget {
  const MyCupertinoPage({super.key});

  @override
  Widget build(BuildContext context) {

    // Scaffold => Android
    // CupertinoPageScaffold => iOS
    // MaterialPageRoute => Android
    // CupertinoPageRoute => iOS
    return CupertinoPageScaffold(
      child: Center(
        child: ElevatedButton(
          onPressed: () => {_showModalView(context)},
          child: Text("SHOW"),
        ),
      ),
    );
  }

  void _showModalView(BuildContext context) { ... }
}

データを受け渡す

アラートやモーダル側にデータを渡す場合は引数に指定すればOKですが、アラートやモーダル側で入力された値などを呼び出し元に渡すことも可能になっています。方法は簡単でawaitを使用して結果を待機させ、モーダル側ではNavigator.pop(データ)形式で実装するだけです。

Future<void> _showMyModal(BuildContext context) async {
  // 返り値としてpopで指定した値を取得することができる
  final result = await showModalBottomSheet<String>(
    context: context,
    builder: (context) {
      return Container(
        padding: EdgeInsets.all(16),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text("値を返します"),
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).pop("モーダルからの値");
              },
              child: Text("閉じる"),
            ),
          ],
        ),
      );
    },
  );

  if (result != null) {
    print("モーダルから受け取った値: $result");
  }
}

// 呼び出し
_showMyModal(context);

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index