📖

FlutterのDialogを不用意に閉じないようにする

2021/05/17に公開

うっかり自分の予想外のタイミングでDialogが閉じることがあるので、
それを防ぐ方法をまとめました。

考慮してない導線だったりして、バグの原因になったりしますからね。

FlutterでDialogを閉じる方法

主に以下の3種類です。

  1. Navigator.of(context).pop()を発火
  2. Dialogの周囲の黒い部分をタップ
  3. Androidの戻るボタンや画面端スワイプによる戻る動作

Dialogを閉じたい時は、基本的にDialog内の閉じるボタンを押下して、上記のNavigator.of(context).pop()を発火させることばかりだと思います。

しかし、上記の2、3のように意図しないタイミングでDialogを閉じてしまい、次の処理が行えないことがあり得ると思います。

Dialogを不用意に閉じないようにする。

以下のDialog表示用の共通関数を定義して使います。

import 'package:flutter/material.dart';

class DialogUtil {
  static Future<void> show({
    required BuildContext context,
    required Widget Function(
      BuildContext context,
    )
        builder,
  }) async {
    await showDialog(
      /// Dialogの周囲の黒い部分をタップしても閉じないようにする
      barrierDismissible: false,
      context: context,
      builder: (_context) {
        return WillPopScope(
          /// 戻るボタンを無効にする
          onWillPop: () async => false,
          child: builder(_context),
        );
      },
    );
  }
}

以下のように使用します。

import 'package:flutter/material.dart';

import 'dialog_util.dart';

class MyHomePage extends StatelessWidget {
  void _handlePressActionButton(BuildContext context) async {
    await DialogUtil.show(
      context: context,
      builder: (BuildContext context) {
        return SimpleDialog(
          title: Text("Dialog"),
          children: [
            TextButton(
              child: Text('close'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            )
          ],
        );
      },
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () => _handlePressActionButton(context),
        tooltip: 'Increment',
        child: Icon(Icons.menu),
      ),
    );
  }
}

Discussion