[Fluth]Wave Animationの実装



FluthのAnimatedBuilderとCustom Painterで実現したWaveアニメーションを使用します.

コード#コード#

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

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

  
  _Animation10State createState() => _Animation10State();
}

class _Animation10State extends State<Animation10> with SingleTickerProviderStateMixin {
  late AnimationController _animationController;

  
  void initState() {
    // TODO: implement initState
    super.initState();
    _animationController = AnimationController(
        vsync: this,
        duration: Duration(seconds: 2)
    );
    _animationController.repeat();
  }
  
  
  void dispose(){
    _animationController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Animation 10"),
      ),
      body: Center(child: _buildBody()),

    );
  }

  Widget _buildBody() {
    return AnimatedBuilder(
      animation: _animationController,
      builder: (context, child) {
        return Container(
          width: 250,
          height: 250,
          color: Colors.lightGreen,
          child: CustomPaint(
            painter: _painter(
              animationValue: _animationController.value
            ),
          ),
        );
      },
    );
  }
}

class _painter extends CustomPainter {
  final animationValue;

  _painter({required this.animationValue});

  
  void paint(Canvas canvas, Size size) {
    double heightParameter = 30;
    double periodParameter = 0.5;

    Paint paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;

    Path path = Path();
    // TODO: do operations here

    for(double i=0; i<250; i++){
      path.lineTo(i,125 + heightParameter*sin(animationValue*pi*2+periodParameter*i*(pi/180)) );
      path.moveTo(i, 0);
    }
    path.close();

    canvas.drawPath(path, paint);
  }

  
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
コードを順番に見てみましょう.

Animation Controller

late AnimationController _animationController;
FluthでAnimationを実現するには、ほとんど必要なクラスです.
lateを宣言した理由はinitState()が初期化されるためです.
アニメーションコントローラが知っておくべき部分はdurationと.価値です.
durationアニメーションの持続時間を設定します.
アニメーションコントローラは次のとおりです.valueという属性が保持されている場合、値は0から1に増加し、duration中に増加します.

Animated Builder

AnimatedBuilder(
      animation: _animationController,
      builder: (context, child) {
        return Container(
          width: 250,
          height: 250,
          color: Colors.lightGreen,
          child: CustomPaint(
            painter: _painter(
              animationValue: _animationController.value
            ),
          ),
        );
      },
    )
Animation Builderの必須プロパティには、アニメーションとジェネレータが含まれます.
アニメーションをアニメーションコントローラに渡します.

CustomPaint

Container(
          width: 250,
          height: 250,
          color: Colors.lightGreen,
          child: CustomPaint(
            painter: _painter(
              animationValue: _animationController.value
            ),
          ),
        )
class _painter extends CustomPainter {
  final animationValue;

  _painter({required this.animationValue});

  
  void paint(Canvas canvas, Size size) {
    double heightParameter = 30;
    double periodParameter = 0.5;

    Paint paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;

    Path path = Path();
    // TODO: do operations here

    for(double i=0; i<250; i++){
      path.lineTo(i,125 + heightParameter*sin(animationValue*pi*2+periodParameter*i*(pi/180)) );
      path.moveTo(i, 0);
    }
    path.close();

    canvas.drawPath(path, paint);
  }

  
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Custom PaintをContainerの子として作成すると、ContainerはCanvasになります.
250*250サイズに設定しました.実行時に中央で適切に見えるようにしたいからです.
painterclassのanimationValueという2値属性を作成します.
painterclassを生成する場合は、その値を渡し、animationcontrollerの値に入れる必要があります.
for(double i=0; i<250; i++){
      path.lineTo(i,125 + heightParameter*sin(animationValue*pi*2+periodParameter*i*(pi/180)) );
      path.moveTo(i, 0);
    }
waveを描いた部分です
sin関数の係数を適切に調整すればよい.
ここで,animationValueは0から1の間の値であり,周期に合わせるために2 piを乗じている.
様々な組合せの係数で実行すると,周期が長い方が自然に見える.
完成しました.
次はもっと面白いことをします.