[読書会]コンテナのプロパティによるアニメーション化

1.概要

 Containerクラスは、特定のプロパティを持つウィジェットを簡単に作成する方法を提供します。
(例えば、width(幅)、height(高さ)、背景色、パディング、境界線などを設定できます。)

 多くのシンプルなアニメーションは、これらのプロパティ時間の経過とともに変更することで実現されます。

(例えば、ユーザがアイテムを選択したことを示す為に、背景色を灰色から緑に変えるアニメーションを作成したいとします。
その為に、Flutterは AnimatedContainer ウィジェットを提供しています。AnimatedContainer は、通常の Container ウィジェットと同じように幅や高さ、背景色などを定義できます。
しかし、AnimatedContainer は再構築されて新しいプロパティが設定されると、古い値から新しい値までを自動でアニメーションします。Flutterでは、このようなアニメーションを「暗黙的アニメーション(implicit animations)」と呼びます。)

2.デフォルトプロパティを持つ StatefulWidget の作成

 ここでは、StatefulWidget と State クラスに実装するアニメーション基本的設定について触れています。
(特に、アニメーションを動的制御用の(State クラス内に実装する)プロパティ変化定義)

アニメーションを動的制御用の(State クラス内に実装する)プロパティ変化定義(例):
class _AnimatedContainerAppState extends State<AnimatedContainerApp> {
  //プロパティ初期値定義:
  //( FloatingActionButtonタップ時、プロパティ更新 )
  double _width = 50; //初期幅
  double _height = 50; //初期高さ
  Color _color = Colors.green; //初期色
  //初期ボーダー半径
  BorderRadiusGeometry _borderRadius = BorderRadius.circular(8);

  @override
  Widget build(BuildContext context) {

3.AnimatedContainer プロパティを使用した構築

 (上記手順での)定義済みプロパティを使用し、AnimatedContainer を構築します。
加えて、アニメーション実行時間定義( duration プロパティ)も行います。

定義済みプロパティを使用した、AnimatedContainer 構築(例):
          child: AnimatedContainer(
            //Stateクラスに定義されたプロパティを使用
            width: _width, //現在の幅
            height: _height, //現在の高さ
            decoration: BoxDecoration(
              color: _color, //現在の背景色
              borderRadius: _borderRadius, //現在のボーダー半径
            ),
            //アニメーションの所要時間を設定(1秒)
            duration: const Duration(seconds: 1),
            //カーブを指定してアニメーションをスムーズに
            curve: Curves.fastOutSlowIn,
          ),

4.新しいプロパティで再構築したアニメーションの開始

 最後に、AnimatedContainer を新しいプロパティで再構築することでアニメーションを開始します
 そのために、setState() メソッドを使用し、ウィジェットの再ビルドを指示し、指定されたプロパティを更新することでアニメーションをトリガーします

 アプリにボタンを追加し、ユーザがそのボタンをタップしたときに、setState() 内で幅、高さ、背景色、ボーダー半径などのプロパティを新しい値で更新するようにします。
(この例では、Random クラスを使用して各プロパティをランダムに変更していますが、実際のアプリでは特定の固定値の間で遷移することが多いです(例えば、背景色をグレーから緑に変更するなど)。)

AnimatedContainer を新しいプロパティで再構築することでアニメーションを開始する(例):
        //FloatingActionButtonを配置
        floatingActionButton: FloatingActionButton(
          //ボタンタップ時処理
          onPressed: () {
            //setStateを使用して新しい値でウィジェットを再構築
            setState(() {
              //ランダムな値を生成するためのランダム生成器を作成
              final random = Random();

              //ランダム値(幅、高さ)生成
              _width = random.nextInt(300).toDouble(); //ランダム幅(0-300)
              _height = random.nextInt(300).toDouble(); // 〃 (0-300)

              //ランダム値(色)生成
              _color = Color.fromRGBO(
                random.nextInt(256), //R成分(0〜255)
                random.nextInt(256), //G成分(0〜255)
                random.nextInt(256), //B成分(0〜255)
                1, //不透明度
              );

              //ランダム値(ボーダー半径)生成
              _borderRadius =
                  BorderRadius.circular(random.nextInt(100).toDouble());
            });
          },
          child: const Icon(Icons.play_arrow), //ボタンアイコン
        ),

5.サンプルコード

AnimatedContainer が再構築されて新しいプロパティを設定し、古い値から新しい値までを自動でアニメーション化(暗黙的アニメーション)する(例):
import 'dart:math';

import 'package:flutter/material.dart';

void main() => runApp(const AnimatedContainerApp());

//メインのアプリウィジェット
class AnimatedContainerApp extends StatefulWidget {
  const AnimatedContainerApp({super.key});

  @override
  State<AnimatedContainerApp> createState() => _AnimatedContainerAppState();
}

class _AnimatedContainerAppState extends State<AnimatedContainerApp> {
  //プロパティ初期値定義:
  //( FloatingActionButtonタップ時、プロパティ更新 )
  double _width = 50; //初期幅
  double _height = 50; //初期高さ
  Color _color = Colors.green; //初期色
  //初期ボーダー半径
  BorderRadiusGeometry _borderRadius = BorderRadius.circular(8);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('AnimatedContainer Demo'), //アプリタイトル
        ),
        body: Center(
          //AnimatedContainerウィジェット:
          //( アニメーション作成 )
          child: AnimatedContainer(
            //Stateクラスに定義されたプロパティを使用
            width: _width, //現在の幅
            height: _height, //現在の高さ
            decoration: BoxDecoration(
              color: _color, //現在の背景色
              borderRadius: _borderRadius, //現在のボーダー半径
            ),
            //アニメーションの所要時間を設定(1秒)
            duration: const Duration(seconds: 1),
            //カーブを指定してアニメーションをスムーズに
            curve: Curves.fastOutSlowIn,
          ),
        ),
        //FloatingActionButtonを配置
        floatingActionButton: FloatingActionButton(
          //ボタンタップ時処理
          onPressed: () {
            //setStateを使用して新しい値でウィジェットを再構築
            setState(() {
              //ランダムな値を生成するためのランダム生成器を作成
              final random = Random();

              //ランダム値(幅、高さ)生成
              _width = random.nextInt(300).toDouble(); //ランダム幅(0-300)
              _height = random.nextInt(300).toDouble(); // 〃 (0-300)

              //ランダム値(色)生成
              _color = Color.fromRGBO(
                random.nextInt(256), //R成分(0〜255)
                random.nextInt(256), //G成分(0〜255)
                random.nextInt(256), //B成分(0〜255)
                1, //不透明度
              );

              //ランダム値(ボーダー半径)生成
              _borderRadius =
                  BorderRadius.circular(random.nextInt(100).toDouble());
            });
          },
          child: const Icon(Icons.play_arrow), //ボタンアイコン
        ),
      ),
    );
  }
}

コメントを残す