🐧

【Flutter入門】コンテナのプロパティをアニメーション化するランダムに

に公開

こんにちは、今回はflutter/cookbookに記載されている「Animate the properties of a container」を体感します!

https://docs.flutter.dev/cookbook/animation/animated-container

面白い機能ですね〜

全体コード(立ち上げ時の初期コードにぶち込んでいます)

import 'dart:math';
import 'package:flutter/material.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'AnimatedContainer Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: 'AnimatedContainer Demo'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: const Center(child: AnimatedContainerApp()),
    );
  }
}

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

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

class _AnimatedContainerAppState extends State<AnimatedContainerApp> {
  double _width = 100;
  double _height = 100;
  Color _color = Colors.green;
  BorderRadiusGeometry _boderRadius = BorderRadius.circular(8);

  void _changeProperties() {
    final random = Random();
    setState(() {
      _width = random.nextInt(200).toDouble() + 50;
      _height = random.nextInt(200).toDouble() + 50;
      _color = Color.fromRGBO(
        random.nextInt(256),
        random.nextInt(256),
        random.nextInt(256),
        1,
      );
      _boderRadius = BorderRadius.circular(random.nextInt(100).toDouble());
    });
  }

  
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        AnimatedContainer(
          width: _width,
          height: _height,
          decoration: BoxDecoration(color: _color, borderRadius: _boderRadius),
          duration: const Duration(seconds: 1),
          curve: Curves.fastOutSlowIn,
        ),
        const SizedBox(height: 20),
        ElevatedButton(
          onPressed: _changeProperties,
          child: const Text('Change Animation'),
        ),
      ],
    );
  }
}

解説のようなメモ

全体構造と目的

・このアプリは「ボタンを押すとAnimatedContainerのサイズ・色・角丸がランダムに変化してアニメーションする」というデモ
・StatefulWidgetを使って状態管理とアニメーションを実現していることに注目する。

Widgetツリー構造

・MyApp/ flutterアプリのエントリーポイント。MaterialAppでアプリ全体のテーマとhomeを設定
・MyHomePage/Scaffoldを使ってタイトル付きのページを作成。
・AnimatedContainerApp/状態管理を持ったStatefulWidget、ここがアニメーションのロジック部分。

StatefulWidgetの使い方

・AnimatedContainerApp と _AnimatedContainerAppState
.Stateクラスに_width,_height,_color,_boderRadiusといった状態(プロパティ)を持っていることがポイント。
・_changeProperitsメソッドでsetstateを読んで値を変更→再描写トリガーにしている。

AnimatedContainer の役割

.AnimatedContainerはプロパティが変わると、自動でスムーズにアニメーションしてくれる便利なウィジェット。
・durationとcurveでアニメーションの速度や動き方を設定している。
・BoxDevotationを受かってcolorとboderRadiusを同時に変化させている

Randomによるプロパティの変更

・Random()を使って幅・高さ・色・角丸をランダムに変化させているところ
・setState()で変更を反映それに伴ってアニメーションが実行される

その他メモ:
【Randomインスタンス】

final random = Random();

Dart標準ライブラリ dart:math から Random() を使い、乱数を生成する準備。
https://dart.dev/libraries/dart-math

【幅・高さのランダム化】

_width = random.nextInt(200).toDouble() + 50;
_height = random.nextInt(200).toDouble() + 50;

random.nextInt(200) で 0~199 の整数値を作り、+50 することで最終的に 50 ~ 249 の範囲に調整している。
toDouble() で double 型に変換して、 AnimatedContainer に渡せるようにしている。

【色のランダム化】

_color = Color.fromRGBO(
  random.nextInt(256),
  random.nextInt(256),
  random.nextInt(256),
  1,
);

RGB 各要素を 0~255 からランダムに生成。
最後の 1 は透明度(alpha)で、完全不透明を指定。

【角丸のランダム化】

_boderRadius = BorderRadius.circular(random.nextInt(100).toDouble());

半径を 0 ~ 99 からランダムに決めて角丸を変化。
数値が大きいほど丸くなる。
※ ここはタイプミスで _boderRadius になっているけど、本来 borderRadius が正しい。

【UI変更トリガー】
これらの変更を setState() 内で行うことで、 AnimatedContainer が自動でアニメーションを開始する仕組みになっている。

Discussion