🚏

ローディング中に背景を暗くしたい

2024/11/24に公開

💡Tips

今月携わっている業務でAPIからデータを取得中に待機していることをユーザーに知らせる機能が必要になった。待機中はインジケーターを表示するのが良くあるなと思いつけてみた。

背景が暗くなるパターンを実装してみた。
https://youtu.be/TMDXxuEDISE

example

DartPadで実行できる完全なデモを作成します。ボタンを押すとローディング状態になり、背景が暗くなってインジケーターが表示される簡単なアプリケーションを作ります。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const LoadingDemo(),
    );
  }
}

class LoadingDemo extends StatefulWidget {
  const LoadingDemo({super.key});

  
  State<LoadingDemo> createState() => _LoadingDemoState();
}

class _LoadingDemoState extends State<LoadingDemo> {
  bool _isLoading = false;

  // API呼び出しをシミュレートする関数
  Future<void> _simulateApiCall() async {
    // ローディング状態を表示
    setState(() => _isLoading = true);
    
    showDialog(
      context: context,
      barrierDismissible: false,
      barrierColor: Colors.black54, // 背景を暗く
      builder: (BuildContext context) {
        return const Center(
          child: CircularProgressIndicator(
            valueColor: AlwaysStoppedAnimation<Color>(Colors.white), // インジケーターを白く
          ),
        );
      },
    );

    // 3秒間の処理時間をシミュレート
    await Future.delayed(const Duration(seconds: 3));

    // ダイアログを閉じる
    if (!mounted) return;
    Navigator.of(context).pop();
    
    setState(() => _isLoading = false);

    // 完了メッセージを表示
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('処理が完了しました')),
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ローディングデモ'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _isLoading ? null : _simulateApiCall,
              child: const Text('処理開始'),
            ),
            const SizedBox(height: 20),
            Text(_isLoading ? '処理中...' : '待機中'),
          ],
        ),
      ),
    );
  }
}

このデモコードには以下の機能が実装されています:

  1. ボタンを押すと処理が開始され、以下の動作が発生します:

    • _isLoading フラグが true になり、ボタンが無効化されます
    • 背景が半透明の黒色(Colors.black54)になります
    • 画面中央に白色のCircularProgressIndicatorが表示されます
    • テキストが「処理中...」に変わります
  2. 3秒後に:

    • ローディング画面が閉じられます
    • _isLoading フラグが false に戻ります
    • 完了メッセージのSnackBarが表示されます
    • テキストが「待機中」に戻ります

このコードはDartPadにそのままコピー&ペーストして実行できます。

元のコードと同様に、mountedチェックも実装し、非同期処理中のウィジェットの状態変更による問題を防いでいます。また、barrierDismissible: falseを設定することで、ローディング中にユーザーが誤ってダイアログを閉じることを防いでいます。

このデモを基に、実際のAPIコールやエラーハンドリングを追加することで、本番環境で使用できるコードに発展させることができます。

Discussion