👀

Flutterで半透明のローディングダイアログを実装する

2023/04/12に公開

Flutterでは、読み込み中などの時に表示を出すインジケーターが標準で備わっています。
https://api.flutter.dev/flutter/material/CircularProgressIndicator-class.html

ですが、これだと基本的には読み込みが完了するまで、インジケーターだけが画面に表示されることになります。こんな感じ。

UI的にはもう一段階工夫できる余地があるかなと思います。
そこで、最近多いのが、インジケータは出しつつ、画面を半透明にして、読み込みが完了するまで画面のコンテンツを表示する方法です。
以下のような感じですね。

やり方は以下の通りです。
1.半透明の画面とCircularProgressIndicatorを、showGeneralDialogにセットする
2.上記で作ったダイアログを呼び出し、続けて非同期で行う操作を記載し、ダイアログを閉じる
3.エラーハンドリングでもダイアログを閉じる

1.半透明の画面とローディングアイコンを、ダイアログにセットする

使いまわせるように、共通のコンポーネントとして作成しましょう。
lib/common とかのフォルダに置いておいておくと良いと思います。

Future <void> showLoadingDialog({
  required BuildContext context,
}) async {
  showGeneralDialog(
      context: context,
      barrierDismissible: false,
      transitionDuration: const Duration(milliseconds: 250), 
      barrierColor: Colors.black.withOpacity(0.5), // 画面マスクの透明度
      pageBuilder: (BuildContext context, Animation animation,
          Animation secondaryAnimation) {
        return  WillPopScope(
          onWillPop: ()async=> false,
          child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const CircularProgressIndicator(),
                  Text(S.of(context)!.processing,style: regularWhite18,),
                ],
              ),
          ),
        );
      });
}

-barrierColor のプロパティにwithOpacityを追加することで、透明度を指定
-WillPopScope を追加すると、処理中に端末の戻るボタンを無効にできます。例えば、課金操作とか、ログイン操作などで、通信中にユーザーの操作を制限したい場合などに使えます。

2.上記で作ったダイアログを呼び出し、続けて非同期で行う操作を記載し、ダイアログを閉じる

例えば、ログインの場面を想定すると、

 Future<void> _login(BuildContext context) async {

     //ダイアログを呼び出す
     await showLoadingDialog(context: context);
      
     //ログイン処理を行う
     await login();
     
     //ダイアログを閉じる
     Navigator.pop(context);
  }

こんな感じで、非同期でダイアログとログイン操作を呼び出し、ログイン操作が終わったらダイアログが閉じるようにします。

3.エラーハンドリングでもダイアログを閉じる

  Future<void> _login(BuildContext context) async {
    try {
      await showLoadingDialog(context: context);
      
     await login();
     
      Navigator.pop(context);
    } catch (e) {
      //ダイアログを閉じる(追加)
      Navigator.pop(context);
  }

try~catchの中にNavigator.popを実装しておき、もし、ログイン処理でエラーが発生した場合でも、ダイアログを閉じる処理を追加しておきます。これがないと、エラー発生時にローディングが回ったままになってしまいます(ここは意外と盲点)

というわけで、以上です。

PS)手前味噌ですが、上記のGIF動画は、私が作成した筋トレ習慣化アプリの画面です。
筋トレ好き、筋トレこれから頑張りたい人は、よかったら使ってみてください〜★
◆Ios
https://apps.apple.com/jp/app/fitness-slave/id1664027797

◆Android
https://play.google.com/store/apps/details?id=net.japanblog.fitness.slave

Discussion