🔦

[Flutter] パッケージを使わず、自動で閉じるダイアログを簡単に実装する方法

2022/02/13に公開

Flutter 2.8.3(stable)
Dart 2.15.1 (stable)

一番最初に思いつくのはこれですが、ダイアログ側で Navigator.pop() されることを考慮できていません。

showDialog<void>();
await Future.delay(const Duration(second: 2));
Navigator.pop();

以上の実装ではなく、ダイアログ側で Navigator.pop() されることを考慮した実装を紹介します。
不適切な言葉、実装の不備などがあった場合は、ご指摘くださると喜びます。

お品書き

  • showDialog に timeout を設定する方法。
    • めっちゃ簡単なので、手っ取り早く実装したい場合はおすすめです。
  • Navigator.overlay?.insert()Overlay を表示する方法(アニメーションなし)。
    • showDialog と表示が少し違うので、こっちの方を実装した方がいい場合があるかもしれません。
  • [応用] 同じ Overlay の実装で、 Toast アニメーションの実装。

showDialog に timeout を設定する方法



show_auto_dispose_dialog.dart
import 'package:flutter/material.dart';
import 'dart:async';

Future<void> showAutoDisposeDialog(BuildContext context) async {
  const displayTime = Duration(seconds: 2);
  
  try {
    await showDialog(
      context: context,
      builder: (_) => const _Dialog()
    )
    .timeout(displayTime);

  } on TimeoutException { // import 'dart:async'; することで、利用可能になります。
    Navigator.of(context).pop();
  }
}

// ダイアログ側の「閉じる」ボタン
Navigator.of(context).pop();
解説

Future である showDialog 、(やってることは Navigator.push()) の返り値は Route.pop です[1]
つまり、遷移先で pop されるまで、showDialog は return されません。
それを利用して、showDialog.timeout で制限時間、ここでは2秒、を設けることで、「2秒以内にちゃんと return しろよ」という実装にします。
そして、on TimeoutException 、つまり制限時間を過ぎた場合に、ダイアログを閉じる処理を書きます(TimeoutException ではなく Exception でも可能ですが、こちらの方が意図が明確なのでおすすめです)。
これで、「ダイアログ側で 2秒以内に pop されなければ、pop する」という機能を実現しています。



show_overlay_auto_dispose_dialog.dart
import 'package:flutter/material.dart';
import 'dart:async';

// ファイルのローカル変数として、 OverlayEntry を宣言。
final _overlayEntry = OverlayEntry(
  builder: (_) => const _Dialog(),
);

void showOverlayToast(BuildContext context) {
  if (_overlayEntry.mounted) return;

  Navigator.of(context).overlay?.insert(_overlayEntry);
  
  // Timer で 2 秒後に実行。
  Timer(const Duration(seconds: 2), () {
    // .mounted で、手動で閉じていない場合だけ、閉じる実行をする。
    if (_overlayEntry.mounted) _overlayEntry.remove();
  });
}
// ダイアログ側の「閉じる」ボタン
_overlayEntry.remove();
解説

showDialog みたいに黒背景とかにならずに、ページに被さるように表示されます。
MaterialPageRouteDialogRoute みたいに push や pop r

[応用] 同じ Overlay の実装で、 Toast アニメーションの実装。




ソースコードは以下にあるので、参考にしてください。
https://github.com/Zudah228/flutter_workspace/blob/master/lib/pages/auto_dispose_dialog/widgets/overlay_toast.dart

参考にしたやつ

Flutter の PageRoute についてわかりやすく書かれた記事。
https://t.co/QfBr3VcyTY
Toast の UI 構築の参考。
https://github.com/PonnamKarthik/FlutterToast

株式会社ドリグロでは新しい仲間となるエンジニア/PM/デザイナーを募集しております。
こちらから以下の内容とともにお気軽にご応募ください。
①どの勤務形態(正社員・アルバイト・業務委託など)に興味があるか
②対応開発言語やその他スキルと各経験年数
③生年月日・最終学歴

脚注
  1. 公式ドキュメントより引用すると、「Returns a Future that completes to the result value passed to pop when the pushed route is popped off the navigator.」
    ソースコードを見ても、push で return されているものは、 route.popped となっている。 ↩︎

Discussion