【スプラッシュ画面】アプリ起動時に黒背景・中央ロゴ・説明文を表示する
この節で学ぶこと
前の節では、logo.svg と icon.png をFlutterアプリで使えるようにする方法を確認しました。
今回の節では、アプリを起動したときに最初に表示される スプラッシュ画面 を見ていきます。
スプラッシュ画面とは、アプリを開いた直後に表示される最初の画面です。
今回のNETAFLIX風アプリでは、次のような画面を表示します。
黒い背景
↓
中央にロゴ
↓
ロゴの下に小さな説明文
↓
少し待つ
↓
Home画面へ移動
アプリを開いた瞬間の印象は、とても大切です。
いきなりHome画面が出るよりも、黒い画面にロゴがふわっと表示されるだけで、少しアプリらしい雰囲気になります。
今回のスプラッシュ画面では、ただロゴを置くだけではなく、フェード表示 と 少し拡大する動き も入れています。
完成イメージ
今回作るスプラッシュ画面は、次のような構成です。
| 要素 | 内容 |
|---|---|
| 背景 | 黒 |
| 中央 | NETAFLIXロゴ |
| ロゴの下 | 「このアプリは授業の一環で作成しました。」 |
| 動き | ふわっと表示され、少し大きくなる |
| 次の画面 | 約2.2秒後にHome画面へ移動 |
見た目としてはシンプルです。
ただ、シンプルな中にも「アプリを開いた感じ」が出るので、完成度が高く見えます。
スプラッシュ画面のコードを見てみよう
今回使っているコードはこちらです。
class SplashScreen extends StatefulWidget {
const SplashScreen({super.key});
@override
State<SplashScreen> createState() => _SplashScreenState();
}
まず、SplashScreen は StatefulWidget として作っています。
StatefulWidget は、画面の状態が変わるときに使います。
今回の場合は、
ロゴをふわっと表示する
少し大きくする
一定時間後に画面を切り替える
という動きがあります。
そのため、StatelessWidget ではなく、StatefulWidget を使っています。
StatefulWidgetとは?
StatefulWidget は、簡単に言うと 途中で変化できる画面 です。
たとえば、次のような場合に使います。
| 使う場面 | 例 |
|---|---|
| ボタンを押したら表示が変わる | Likeボタン |
| 入力した文字で結果が変わる | Search画面 |
| アニメーションする | スプラッシュ画面 |
| 数秒後に画面が変わる | 起動画面からHomeへ移動 |
今回のスプラッシュ画面では、時間とともにロゴの見え方が変わります。
そのため、StatefulWidget が必要になります。
アニメーションを管理する準備
次に、この部分を見てみましょう。
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin {
late final AnimationController animationController;
late final Animation<double> fadeAnimation;
late final Animation<double> scaleAnimation;
少し長く見えますが、ここではアニメーションに必要な道具を用意しています。
| コード | 役割 |
|---|---|
AnimationController | アニメーション全体の時間を管理する |
fadeAnimation | 透明から表示される動きを作る |
scaleAnimation | 少し小さい状態から通常サイズにする |
SingleTickerProviderStateMixin | アニメーションを動かすための準備 |
最初は、細かい意味を全部覚えなくて大丈夫です。
まずは、
AnimationControllerがアニメーションの司令塔
fadeAnimationがふわっと表示
scaleAnimationが少し大きくなる動き
くらいでOKです。
initStateで最初の処理を書く
次は initState() です。
@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 900),
);
initState() は、その画面が表示されるときに最初に一度だけ実行される場所です。
スプラッシュ画面では、表示された瞬間にアニメーションを準備したいので、ここに書いています。
この部分では、アニメーションの長さを決めています。
duration: const Duration(milliseconds: 900),
これは、
アニメーションを900ミリ秒で動かす
という意味です。
900ミリ秒は、0.9秒です。
速すぎず、遅すぎず、ロゴが自然に表示されるくらいの時間です。
フェード表示を作る
次に、ロゴがふわっと出る動きです。
fadeAnimation = CurvedAnimation(
parent: animationController,
curve: Curves.easeOut,
);
fadeAnimation は、透明な状態から見える状態に変わるためのアニメーションです。
Curves.easeOut は、動きの雰囲気を決めています。
easeOut は、最初に少し速く動いて、最後にゆっくり止まるような動きです。
いきなりパッと出るよりも、少し自然に見えます。
少し拡大する動きを作る
次に、ロゴが少し小さい状態から、自然な大きさになる動きです。
scaleAnimation = Tween<double>(
begin: 0.94,
end: 1.0,
).animate(
CurvedAnimation(
parent: animationController,
curve: Curves.easeOutBack,
),
);
ここでは、ロゴの大きさを変えています。
| 値 | 意味 |
|---|---|
begin: 0.94 | 最初は少し小さい |
end: 1.0 | 最後は通常サイズ |
Curves.easeOutBack | 少し弾むような自然な動き |
つまり、ロゴは最初に少し小さく表示されて、ふわっと通常サイズになります。
このような小さな動きがあるだけで、アプリの印象がかなり変わります。
アニメーションを開始する
アニメーションの準備ができたら、次のコードで動かします。
animationController.forward();
これは、
アニメーションを最初から最後まで再生してください
という意味です。
この1行がないと、アニメーションは準備されていても動きません。
約2.2秒後にHome画面へ移動する
スプラッシュ画面は、ずっと表示する画面ではありません。
少し見せたら、Home画面へ移動します。
その処理がこちらです。
Future<void>.delayed(const Duration(milliseconds: 2200), () {
if (!mounted) {
return;
}
Navigator.of(context).pushReplacement(
PageRouteBuilder<void>(
pageBuilder: (context, animation, secondaryAnimation) {
return const NetflixShellPage();
},
transitionDuration: const Duration(milliseconds: 420),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final curvedAnimation = CurvedAnimation(
parent: animation,
curve: Curves.easeOut,
);
return FadeTransition(
opacity: curvedAnimation,
child: child,
);
},
),
);
});
少し長いですが、流れはシンプルです。
2.2秒待つ
↓
まだ画面が存在しているか確認する
↓
Home画面へ移動する
↓
そのときにフェードで切り替える
ここで使っている pushReplacement は、今の画面を次の画面に置き換えるためのものです。
スプラッシュ画面は、Home画面に移動したあと戻る必要がありません。
そのため、普通の push ではなく、pushReplacement を使っています。
mountedとは?
この部分も大切です。
if (!mounted) {
return;
}
mounted は、その画面がまだ存在しているかを確認するためのものです。
たとえば、2.2秒待っている間に画面が閉じられた場合、そのあとに画面遷移しようとするとエラーになることがあります。
そのため、
まだこの画面が使える状態なら処理を続ける
もう使えないなら何もしない
という確認をしています。
最初は難しく感じるかもしれませんが、時間差で処理をするときにはよく出てくる安全チェックです。
画面の見た目を作る
次に、実際の見た目を作っている部分です。
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: NetflixColors.black,
body: SafeArea(
child: Center(
child: FadeTransition(
opacity: fadeAnimation,
child: ScaleTransition(
scale: scaleAnimation,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const NetflixWordLogo(height: 54),
const SizedBox(height: 18),
Text(
'このアプリは授業の一環で作成しました。',
textAlign: TextAlign.center,
style: TextStyle(
color: NetflixColors.white.withValues(alpha: 0.72),
fontSize: 12,
fontWeight: FontWeight.w600,
letterSpacing: 0.4,
),
),
],
),
),
),
),
),
);
}
この部分で、黒背景、中央ロゴ、説明文を表示しています。
順番に見ていきましょう。
背景を黒にする
背景色はここで決めています。
backgroundColor: NetflixColors.black,
NetflixColors.black は、アプリ全体で使う黒色です。
色を直接、
Colors.black
と書いても動きます。
ただし、今回のコードでは色を NetflixColors にまとめています。
こうしておくと、アプリ全体の色を管理しやすくなります。
SafeAreaで画面の端を避ける
次に出てくるのが SafeArea です。
body: SafeArea(
child: Center(
SafeArea は、スマホのノッチやステータスバーに重ならないようにするためのWidgetです。
最近のスマホは、画面上部にカメラ部分やステータスバーがあります。
そこに文字やボタンが重なると見づらくなります。
SafeArea を使うと、そのような場所を避けて表示してくれます。
今回は中央表示なので大きな問題にはなりにくいですが、スマホアプリではよく使うWidgetです。
Centerで中央に配置する
次に、Center です。
child: Center(
これは、中の要素を画面の中央に置くためのWidgetです。
今回の場合は、ロゴと説明文を画面の真ん中に置きたいので使っています。
とてもよく使うWidgetなので、覚えておくと便利です。
FadeTransitionでふわっと表示する
この部分で、透明から見える状態にしています。
FadeTransition(
opacity: fadeAnimation,
FadeTransition は、透明度を変えるアニメーションです。
opacity に fadeAnimation を渡すことで、最初は見えない状態から、だんだん見える状態になります。
スプラッシュ画面でよく使われる表現です。
ScaleTransitionで少し拡大する
次は ScaleTransition です。
ScaleTransition(
scale: scaleAnimation,
ScaleTransition は、大きさを変えるアニメーションです。
今回の場合は、
少し小さい
↓
通常サイズ
という動きになります。
FadeTransition と ScaleTransition を組み合わせることで、ロゴが自然に出てくるように見えます。
Columnでロゴと説明文を縦に並べる
ロゴと説明文は、Column で縦に並べています。
Column(
mainAxisSize: MainAxisSize.min,
children: [
const NetflixWordLogo(height: 54),
const SizedBox(height: 18),
Text(
'このアプリは授業の一環で作成しました。',
),
],
)
Column は、上から下に並べるためのWidgetです。
今回の並びはこうです。
ロゴ
↓
余白
↓
説明文
間の余白は、こちらで作っています。
const SizedBox(height: 18),
SizedBox は、余白を作るときによく使います。
mainAxisSize: MainAxisSize.min とは?
この部分も見ておきましょう。
mainAxisSize: MainAxisSize.min,
Column は、何も指定しないと、縦方向に大きく広がろうとします。
でも今回は、ロゴと説明文の分だけの高さで十分です。
そのため、
mainAxisSize: MainAxisSize.min
を指定して、必要な分だけの高さにしています。
細かいですが、中央配置をきれいに見せるために大切な指定です。
ロゴを表示する
ロゴは、前の節でも出てきた NetflixWordLogo を使っています。
const NetflixWordLogo(height: 54),
これは、assets/images/logo.svg を表示するための部品です。
height を変えると、ロゴの大きさが変わります。
たとえば、
const NetflixWordLogo(height: 70),
にすると、ロゴが大きくなります。
アプリの第一印象を変えたいときは、この数字を少し調整してみると分かりやすいです。
説明文を表示する
ロゴの下には、説明文を表示しています。
Text(
'このアプリは授業の一環で作成しました。',
textAlign: TextAlign.center,
style: TextStyle(
color: NetflixColors.white.withValues(alpha: 0.72),
fontSize: 12,
fontWeight: FontWeight.w600,
letterSpacing: 0.4,
),
),
この文章は、授業用のアプリであることを伝えるために入れています。
ここでは、文字を少し控えめに表示しています。
| 指定 | 内容 |
|---|---|
color | 白を少し薄くして表示 |
fontSize: 12 | 小さめの文字 |
fontWeight: FontWeight.w600 | 少しだけ太め |
letterSpacing: 0.4 | 文字の間を少し広げる |
ロゴを主役にしたいので、説明文は少し控えめにしてあります。
disposeで片付ける
アニメーションを使ったら、最後に片付けが必要です。
@override
void dispose() {
animationController.dispose();
super.dispose();
}
AnimationController は、画面がなくなったあとも残ってしまうとよくありません。
そのため、画面を閉じるタイミングで dispose() を呼び出して片付けます。
これは少し地味ですが、とても大切です。
アニメーションやコントローラーを使ったら、最後に片付ける。
この考え方は、今後もいろいろな場面で出てきます。
スプラッシュ画面を最初に表示する設定
スプラッシュ画面を作っただけでは、アプリ起動時に表示されません。
MaterialApp の home に指定する必要があります。
home: const SplashScreen(),
今回のコードでは、最初に SplashScreen を表示しています。
そのあと、SplashScreen の中で約2.2秒待ってから、NetflixShellPage に移動します。
流れはこうです。
MaterialApp
↓
SplashScreen
↓
NetflixShellPage
↓
Home / Clips / Search / My Netaflix
この流れをつかむと、アプリ全体の動きが分かりやすくなります。
まずカスタマイズしてみよう
今回は、スプラッシュ画面の表示時間を変えてみましょう。
次のコードを探してください。
Future<void>.delayed(const Duration(milliseconds: 2200), () {
この 2200 は、2.2秒を表しています。
たとえば、3秒表示したい場合は、次のようにします。
Future<void>.delayed(const Duration(milliseconds: 3000), () {
保存して、アプリを再起動してください。
スプラッシュ画面が少し長く表示されるようになります。
ロゴの大きさもカスタマイズしてみよう
次に、ロゴの大きさを変えてみます。
const NetflixWordLogo(height: 54),
これを、少し大きくしてみましょう。
const NetflixWordLogo(height: 70),
保存して、アプリを再起動します。
ロゴが大きくなっていれば成功です。
大きすぎると感じたら、
const NetflixWordLogo(height: 60),
くらいにすると、バランスが取りやすいです。
説明文をカスタマイズしてみよう
次は、ロゴの下に出る説明文を変えてみます。
変更前はこちらです。
'このアプリは授業の一環で作成しました。'
たとえば、次のように変えることができます。
'Flutterの授業で作成した動画アプリ風UIです。'
保存して、アプリを再起動してください。
ロゴの下の説明文が変わっていればOKです。
よくあるつまずきポイント
Q. スプラッシュ画面が表示されません。
MaterialApp の home が SplashScreen になっているか確認してください。
home: const SplashScreen(),
もしここが、
home: const NetflixShellPage(),
になっていると、スプラッシュ画面を飛ばして、すぐにHome画面が表示されます。
Q. ロゴが表示されません。
まず、ロゴファイルの場所を確認してください。
assets/images/logo.svg
次に、pubspec.yaml にアセット登録があるか確認します。
flutter:
uses-material-design: true
assets:
- assets/images/
さらに、main.dart に次のimportがあるか確認してください。
import 'package:flutter_svg/flutter_svg.dart';
Q. アプリが画面遷移しません。
この部分があるか確認してください。
Navigator.of(context).pushReplacement(
PageRouteBuilder<void>(
pageBuilder: (context, animation, secondaryAnimation) {
return const NetflixShellPage();
},
),
);
また、Future<void>.delayed の時間が極端に長くなっていないかも見ておきましょう。
たとえば、
Duration(milliseconds: 30000)
だと、30秒待つことになります。
Q. エラーが出たらどこを見ればいいですか。
まずは、直前に変更した場所を見ます。
特に次のミスがよくあります。
| よくあるミス | 内容 |
|---|---|
| カンマ忘れ | const NetflixWordLogo(height: 70) の後に , がない |
| かっこ不足 | ) や } が足りない |
| 文字列の閉じ忘れ | 'Flutterの授業で作成した動画アプリ風UIです。 |
| クラス名の間違い | Splashscreen と SplashScreen の違い |
Flutterでは、大文字と小文字も区別されます。
SplashScreen と Splashscreen は別物として扱われます。
チャレンジ
チャレンジ1:スプラッシュ画面の表示時間を3秒にしよう
次のコードを探してください。
Future<void>.delayed(const Duration(milliseconds: 2200), () {
これを、3秒に変更してみましょう。
チャレンジ2:ロゴを少し大きくしよう
次のコードを探してください。
const NetflixWordLogo(height: 54),
これを次のように変えてみましょう。
const NetflixWordLogo(height: 70),
チャレンジ3:説明文を自分の言葉に変えよう
次の文章を探します。
'このアプリは授業の一環で作成しました。'
これを、自分の好きな説明文に変えてみましょう。
例:
'Flutterで作成した動画アプリ風UIです。'
チャレンジ4:アニメーションを少しゆっくりにしよう
次のコードを探してください。
duration: const Duration(milliseconds: 900),
これを次のように変更します。
duration: const Duration(milliseconds: 1400),
ロゴの表示が少しゆっくりになります。
チャレンジの答え
チャレンジ1の答え
変更前:
Future<void>.delayed(const Duration(milliseconds: 2200), () {
変更後:
Future<void>.delayed(const Duration(milliseconds: 3000), () {
これで、スプラッシュ画面が約3秒表示されます。
チャレンジ2の答え
変更前:
const NetflixWordLogo(height: 54),
変更後:
const NetflixWordLogo(height: 70),
これで、中央のロゴが大きくなります。
チャレンジ3の答え
変更前:
'このアプリは授業の一環で作成しました。'
変更後の例:
'Flutterで作成した動画アプリ風UIです。'
ロゴ下の説明文が変わります。
チャレンジ4の答え
変更前:
duration: const Duration(milliseconds: 900),
変更後:
duration: const Duration(milliseconds: 1400),
ロゴがゆっくり表示されるようになります。
この節のまとめ
この節では、アプリ起動時に表示されるスプラッシュ画面を確認しました。
大切なポイントは次の通りです。
- スプラッシュ画面は、アプリを開いた直後に表示される最初の画面。
- 今回は黒背景、中央ロゴ、説明文を表示している。
StatefulWidgetを使うことで、アニメーションや時間差の処理ができる。AnimationControllerは、アニメーション全体の時間を管理する。FadeTransitionは、ふわっと表示する動きを作る。ScaleTransitionは、少し拡大する動きを作る。Future.delayedを使うと、一定時間後に処理を実行できる。pushReplacementを使うと、スプラッシュ画面からHome画面へ置き換えることができる。dispose()でアニメーションの片付けをすることも大切。
次のステップ
次の節では、アプリ全体の見た目を決める テーマ設計 を学びます。
黒背景、赤いアクセント、白い文字をどのように管理しているのかを見ていきます。
次は、NETAFLIX風アプリの世界観を作っている「色」と「テーマ」の部分を確認していきましょう。
