😎

Flutterでお手軽なローディングUIの実装

2024/01/23に公開

Flutterでお手軽なローディングUIの実装

非同期処理中にawaitで待っている間、全画面を覆うくるくるUIを実装

SwiftのSVProgressHUDのように手軽に、ローディングUIを使いたい

https://github.com/SVProgressHUD/SVProgressHUD

実装後の利用例

LoadingDialog.show(context); // 表示
await Future.delayed(Duration(seconds: 5)); // API通信処理など
LoadingDialog.hide(context); // 非表示

実装

  • LoadingDialogクラスを作成
// 「ローディング」表示のView(ダイアログ)
// 使い方)
//   // ローディング表示
//   LoadingDialog.show(context);
//   // 非同期処理を実行
//   await Future.delayed(Duration(seconds: 5));
//   // ローディングを非表示
//   LoadingDialog.hide(context);
class LoadingDialog extends StatefulWidget {
  
  _LoadingDialogState createState() => _LoadingDialogState();

  static void show(BuildContext context) {
    showDialog(
      context: context,
      barrierDismissible: false,
        builder: (BuildContext context) {

          // NOTE: ↓Flutter v3.16.0~ Deprecated
          // 「Android実機の戻るボタン」を無効にする(NOTE: Flutter v3.16.0以前の実装方法)
          // return WillPopScope(
          //   onWillPop: () async => false,
          //   child: LoadingDialog()
          // );

          // 「Android実機の戻るボタン」を無効にする(NOTE: Flutter v3.16.0~)
          return PopScope(
              canPop: false,
              child: LoadingDialog(),
          );
      }
    );
  }

  static void hide(BuildContext context) {
    Navigator.of(context).pop();
  }
}

class _LoadingDialogState extends State<LoadingDialog> {

  
  Widget build(BuildContext context) {
    return Center(
      child: SizedBox(
        width: 150,
        height: 150,
        child: AlertDialog(
          // backgroundColor: Colors.green, // MEMO: 背景色の指定
          alignment: Alignment.center,
          contentPadding: EdgeInsets.zero,
          insetPadding: EdgeInsets.zero,
          content: _dialogContent(),
        ),
      ),
    );

  }

  // ダイアログ内に表示するWidget
  Widget _dialogContent() {
    return Container(
      child: Column(
        children: [
          Spacer(),
          CircularProgressIndicator(),
          Spacer(),
          Text('Loading...'),
          // Text('Loading...', style: TextStyle(fontSize: 18,fontWeight: FontWeight.w100),),
          Spacer(),
        ],
      ),
    );
  }
}

ポイント

  • Adnroid実機の戻るボタン(スワイプで戻る)を、無効化する実装
  • Dialogのcontent設定時に、DefaultのPadding値を無効化する実装

その他

  • 引数でcontext必須のため、基本的にUI層で使うことを想定。
    (Widget以外で使いたい場合、contextをバケツリレーで渡すか、GlobalKey使っていつでもcontextにアクセス可能な仕組みを用意?)

  • ダイアログは、設定済のpadding等があるのでそれらを無効にする設定をしないと、widthの小さい値などが、正確に表示されない(contentPadding、insetPaddingの EdgeInsets.zero)

Discussion