【Flutter】初期化が終わるまでスプラッシュ画面を表示したい【flutter_native_splash】


はじめに

アプリを起動したときは様々な初期化をするかと思います。ユーザー認証があればユーザーがログインしているかどうかわかるまで待ったり、データベースからユーザーの情報を読み込んだり、時には初期化に数秒待たせる場合もあります。

ユーザーを待たせている間にスプラッシュ画面を表示するのは良いアプローチです。しかし、flutter_native_splash を使ってスプラッシュ画面を実装をしたものの、初期化処理が終わる前にスプラッシュ画面が閉じてしまってお困りではないでしょうか。

https://pub.dev/packages/flutter_native_splash

ここでは、初期化処理が終わるまでスプラッシュ画面を表示し続ける方法について紹介します。

もし、まだスプラッシュ画面を実装していない方は、是非次の記事を読んでスプラッシュ画面を実装してから本記事に戻ってきて下さい。

https://zenn.dev/susatthi/articles/20220406-061305-flutter-native-splash

結論

初期化の最初と最後に次のコードを追加するだけです。

+import 'package:flutter_native_splash/flutter_native_splash.dart';

void main() {
+  final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
+  FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
  runApp(const MyApp());
}

// 初期化が終了したら次のコードを呼び出す
+FlutterNativeSplash.remove();

次から詳細を説明していきます。

環境

Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision c860cba910 (2 weeks ago) • 2022-03-25 00:23:12 -0500
Engine • revision 57d3bac3dd
Tools • Dart 2.16.2 • DevTools 2.9.2

前提

説明のために、いつものカウントアップアプリに次の機能を追加しました。

  • スプラッシュ画面を実装
  • アプリ起動時にカウント初期値 (10) をサーバーから読み込んで表示する。
    • 本当にサーバーから読み込むとコードが長くなってしまうので、サンプルでは 2 秒間スリープするようにしています。
  • 読み込んでいる間はプログレス表示する。

すると次のようにスプラッシュ画面が閉じた後プログレス表示が出てしまいました。

サンプル動画

コードは次の通りです。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
+  bool _isLoading = true;

+  
+  void initState() {
+    super.initState();
+    Future(() async {
+      await Future<void>.delayed(const Duration(seconds: 2));
+      setState(() {
+        _counter = 10;
+        _isLoading = false;
+      });
+    });
+  }

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
-      body: Center(
+      body: Stack(
+        children: [
+          Visibility(
+            visible: !_isLoading,
+            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Text(
                    'You have pushed the button this many times:',
                  ),
                  Text(
                    '$_counter',
                    style: Theme.of(context).textTheme.headline4,
                  ),
                ],
              ),
            ),
+          ),
+          Visibility(
+            visible: _isLoading,
+            child: Center(
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: const [
+                  CircularProgressIndicator(),
+                ],
+              ),
+            ),
+          )
+        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

修正方法

初期化が終了するまでスプラッシュ画面を表示するように修正してみます。
flutter_native_splash のメソッドを呼びたいので pubspec.yaml を次の通りに修正します。

pubspec.yaml
dependencies:
+  flutter_native_splash: ^2.1.3+1

dev_dependencies:
-  flutter_native_splash: ^2.1.3+1

runApp() の前に次のコードを追加します。

import 'package:flutter/material.dart';
+import 'package:flutter_native_splash/flutter_native_splash.dart';

void main() {
+  final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
+  FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
  runApp(const MyApp());
}

最後に、初期化処理が終了したタイミングで次のコードを追加します。

  
  void initState() {
    super.initState();
    Future(() async {
      await Future<void>.delayed(const Duration(seconds: 2));
      setState(() {
+        FlutterNativeSplash.remove();
        _counter = 10;
        _isLoading = false;
      });
    });
  }

これで修正が完了しました。実際の動きを見てみましょう。

サンプル動画

プログレスが表示されず、初期化処理が終了するまでスプラッシュ画面を表示することが出来ました。是非参考にしてみて下さい!

最後に

Flutter大学というFlutterエンジニアに特化した学習コミュニティに所属しています。興味がある方はこちらのページから参加できます。

https://flutteruniv.com/

あわせて読みたい

https://zenn.dev/susatthi/articles/20220406-061305-flutter-native-splash