📜

【Dart/Flutter】AnimatedWidgetを自作する簡単例(extends AnimatedWidget)

2023/03/12に公開

AnimationController型変数を引数に渡し、AnimatedWidgetを継承したクラスを返す、簡単な例となります。

【Dart/Flutter】AnimatedWidgetを自作する簡単例(extends AnimatedWidget)

AnimatedBuilder抽出前

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const Scaffold(body: MyHomePage()),
    ),
  );
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _animation;

  
  void initState() {
    super.initState();
    _animation = AnimationController(
      duration: const Duration(seconds: 5),
      vsync: this,
    )..repeat();
  }

  
  void dispose() {
    _animation.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Stack(
      alignment: AlignmentDirectional.center,
      children: <Widget>[
        AnimatedBuilder(
          animation: _animation,
          builder: (_, __) {
            return Container(
              color: Colors.red,
              height: 1000 * _animation.value,
            );
          },
        ),
      ],
    );
  }
}

AnimatedBuilder抽出(自作クラス作成)

  • 通常通りIDEの機能等により抽出すると、以下StatelessWidget
class TestTransition extends StatelessWidget {
  const TestTransition({
    Key? key,
    required AnimationController animation,
  }) : _animation = animation, super(key: key);

  final AnimationController _animation;

  
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (_, __) {
        return Container(
          color: Colors.red,
          height: 1000 * _animation.value,
        );
      },
    );
  }
}
  • AnimatedWidgetとするための修正
    • 継承変更
      • extends StatelessWidgetextends AnimatedWidget
    • 親コンストラクタにlistenable追加
      • super(key: key);super(key: key, listenable: animation);
    • build関数内
      • AnimatedBuilderを削除し、上記アニメーション用の変数を利用したWidgetに変更
        • return AnimatedBuilder(...);return Container(...);
class TestTransition extends AnimatedWidget {
  const TestTransition({
    Key? key,
    required AnimationController animation,
  })  : _animation = animation,
        super(key: key, listenable: animation);

  final AnimationController _animation;

  
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      height: 1000 * _animation.value,
    );
  }
}
  • 【参考】引数をthisとする場合 ※同様動作
class TestTransition extends AnimatedWidget {
  const TestTransition({
    Key? key,
    required this.animation,
  }) : super(key: key, listenable: animation);

  final AnimationController animation;

  
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      height: 1000 * animation.value,
    );
  }
}
  • 【参考】参考サイトでは、以下build関数内にアニメーション用の変数を追加 ※同様動作
    • AnimationController animation = listenable as AnimationController;
class TestTransition extends AnimatedWidget {
  const TestTransition({
    Key? key,
    required AnimationController animation,
  }) : super(key: key, listenable: animation);

  
  Widget build(BuildContext context) {
    AnimationController animation = listenable as AnimationController;

    return Container(
      color: Colors.red,
      height: 1000 * animation.value,
    );
  }
}

以下、全文

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const Scaffold(body: MyHomePage()),
    ),
  );
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _animation;

  
  void initState() {
    super.initState();
    _animation = AnimationController(
      duration: const Duration(seconds: 5),
      vsync: this,
    )..repeat();
  }

  
  void dispose() {
    _animation.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Stack(
      alignment: AlignmentDirectional.center,
      children: <Widget>[
        TestTransition(animation: _animation),
      ],
    );
  }
}

class TestTransition extends AnimatedWidget {
  const TestTransition({
    Key? key,
    required this.animation,
  }) : super(key: key, listenable: animation);

  final AnimationController animation;

  
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      height: 1000 * animation.value,
    );
  }
}

【備考】child利用

class TestTransition extends AnimatedWidget {
  const TestTransition({
    Key? key,
    required AnimationController animation,
    required this.child,
  }) : super(key: key, listenable: animation);

  final Widget child;

  
  Widget build(BuildContext context) {
    AnimationController animation = listenable as AnimationController;

    return Container(
      color: Colors.red,
      height: 1000 * animation.value,
      child: child,
    );
  }
}

Discussion