[読書会]ウィジェットのフェードイン/フェードアウト

1.概要

 UI開発者は画面上の要素を表示したり隠したりする必要がよくあります。
しかし、要素を急に画面に表示または非表示にするのは、ユーザーにとって唐突で不快に感じることがあります。
代わりに、不透明度(opacity)アニメーションを使って要素をフェードイン・アウトさせることで、スムーズなユーザー体験を実現できます

 FlutterではAnimatedOpacity ウィジェットを使用することで、不透明度のアニメーションを簡単に行うことができます。このレシピでは、次の手順でフェードイン・アウトを実装します。

2.フェードイン/フェードアウトのボックス作成

 フェードイン・フェードアウトするための要素をまず作成します。
(この例では、画面に緑色のボックスを表示します。以下の Container ウィジェットのコードがその役割を果たします。)

フェードイン/フェードアウトのボックス作成(例):
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title), //アプリバータイトル表示
      ),
      body: Center(
        //アニメーション付きの不透明度ウィジェット
        //( 子要素表示/非表示 のアニメーションによる制御 )
        child: AnimatedOpacity(
          //ボックス表示時 1.0(完全に見える)、非表示時 0.0(見えない)
          opacity: _visible ? 1.0 : 0.0,
          //アニメーション持続時間の設定
          duration: const Duration(milliseconds: 500),
          //AnimatedOpacity の子要素として表示するコンテナ
          child: Container(
            width: 200,
            height: 200,
            color: Colors.green, //緑のボックス
          ),
        ),
      ),

3.StatefulWidget の定義

 StatefulWidget を使って、ボックスが表示されるかどうかを管理します。
StatefulWidget を使用することで、ウィジェットが状態を持ち、その状態に基づいて UI を更新することができます。

 このウィジェットには、ボタンが表示されるかどうかを表す 1 つのブール型データが含まれています。
コードの bool _visible = true; で定義されている変数 _visible は、緑のボックスが表示されるかどうかを表します。

StatefulWidget で、ボックス状態(表示/非表示)フラグを宣言(例):
//StatefulWidget 定義:
//タイトルを受け取り、状態クラスを作成する
class MyHomePage extends StatefulWidget {
  const MyHomePage({
    super.key,
    required this.title, //受け取ったタイトルを保持
  });

  final String title; //タイトルプロパティ

  @override
  State<MyHomePage> createState() => _MyHomePageState(); //状態を生成
}

//State クラス
//( UI と更新可能なデータの管理 )
class _MyHomePageState extends State<MyHomePage> {
  //緑のボックスが表示されているかどうかを保持する変数
  bool _visible = true;

  @override
  Widget build(BuildContext context) {
  

4.表示/非表示を切替える為のボタン表示

 緑色のボックスが表示されるかどうか切り替えるめに、ユーザが押すボタンを実装する方法を説明しています。

 このボタンは FloatingActionButton を使って実装され、onPressed プロパティコールバック関数を設定します。
ボタン押下時関数が呼び出され_visible の値 true から false、または false から true に切り替わります。)

setState() メソッド呼出により、Flutter にウィジェットを再構築するよう指示し、新しい状態に応じて UI を更新します。
(setState() の呼出により、UI が再構築され、ボックスがアニメーション付きでフェードイン/フェードアウトします。)

緑色のボックスが表示されるかどうかを切り替えるために、ユーザーが押すボタンを実装する(例):
      //FloatingActionButton
      //( 押されると setState が呼ばれて UI が更新される )
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          //setState を呼んで、ウィジェットを新しい状態で再構築する
          setState(() {
            _visible = !_visible; //_visible の値を反転させる
          });
        },
        tooltip: 'Toggle Opacity', //ボタンのツールチップ
        child: const Icon(Icons.flip), //ボタンのアイコン
      ),

5.ボックスのフェードイン/フェードアウト実行

 AnimatedOpacity ウィジェットを使用して、ボックスをフェードイン・アウトさせる方法を解説しています。

 AnimatedOpacity ウィジェットは、UI 要素をスムーズに(透明度を変更することで)表示したり非表示にしたりするアニメーションを提供します。

AnimatedOpacity ウィジェットを使用して、ボックスをフェードイン・アウトさせる(例):
      body: Center(
        //アニメーション付きの不透明度ウィジェット
        //( 子要素表示/非表示 のアニメーションによる制御 )
        child: AnimatedOpacity(
          //ボックス表示時 1.0(完全に見える)、非表示時 0.0(見えない)
          opacity: _visible ? 1.0 : 0.0,
          //アニメーション持続時間の設定
          duration: const Duration(milliseconds: 500),
          //AnimatedOpacity の子要素として表示するコンテナ
          child: Container(
            width: 200,
            height: 200,
            color: Colors.green, //緑のボックス
          ),
        ),
      ),

6.サンプルコード

ボタン押下時にボックスがフェードアウト/フェードインするアニメーション(例):
import 'package:flutter/material.dart';

//アプリのエントリーポイント
void main() => runApp(const MyApp());

//アプリ全体をラップする StatelessWidget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const appTitle = 'Opacity Demo'; //アプリタイトル定義
    return const MaterialApp(
      title: appTitle,
      home: MyHomePage(title: appTitle), //ルートウィジェット設定
    );
  }
}

//StatefulWidget 定義:
//タイトルを受け取り、状態クラスを作成する
class MyHomePage extends StatefulWidget {
  const MyHomePage({
    super.key,
    required this.title, //受け取ったタイトルを保持
  });

  final String title; //タイトルプロパティ

  @override
  State<MyHomePage> createState() => _MyHomePageState(); //状態を生成
}

//State クラス
//( UI と更新可能なデータの管理 )
class _MyHomePageState extends State<MyHomePage> {
  //緑のボックスが表示されているかどうかを保持する変数
  bool _visible = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title), //アプリバータイトル表示
      ),
      body: Center(
        //アニメーション付きの不透明度ウィジェット
        //( 子要素表示/非表示 のアニメーションによる制御 )
        child: AnimatedOpacity(
          //ボックス表示時 1.0(完全に見える)、非表示時 0.0(見えない)
          opacity: _visible ? 1.0 : 0.0,
          //アニメーション持続時間の設定
          duration: const Duration(milliseconds: 500),
          //AnimatedOpacity の子要素として表示するコンテナ
          child: Container(
            width: 200,
            height: 200,
            color: Colors.green, //緑のボックス
          ),
        ),
      ),
      //FloatingActionButton
      //( 押されると setState が呼ばれて UI が更新される )
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          //setState を呼んで、ウィジェットを新しい状態で再構築する
          setState(() {
            _visible = !_visible; //_visible の値を反転させる
          });
        },
        tooltip: 'Toggle Opacity', //ボタンのツールチップ
        child: const Icon(Icons.flip), //ボタンのアイコン
      ),
    );
  }
}

コメントを残す