[Flutter] Wave Animation 구현

RGLie,·2022년 3월 26일
1


Flutter의 AnimatedBuilder와 Custom Painter를 사용하여 구현한 Wave animation이다.

코드

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;

Flutter에서 Animation을 구현하고 싶다면 거의 필수로 필요한 Class이다.
late를 선언해준 이유는 initialize를 initState()에서 해주기 때문이다.

Animation Controller에서 알고 있어야할 부분은 duration과 .value이다.
duration은 Animation의 지속시간을 설정한다.
Animation Controller에는 .value라는 속성이 있는데, 다른 속성을 그대로 두었다면 이 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의 required 속성으로는 animation과 builder가 있다.
animation에는 animation controller를 넘겨주어야한다.

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 사이즈로 설정했다.

painter class에 animationValue라는 double 값을 속성으로 만들어준다.
painter class를 생성할때 이 값을 넘겨줘야하고 그 값을 animationcontroller의 value 값을 넣어주면 된다.

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 사이의 값이므로 주기와 맞춰주기 위해 2pi를 곱해준다.

여러 조합의 계수로 실행해봤는데 주기가 긴것이 조금 더 자연스럽게 보였다.


완성이다.
다음번에는 더 재밌는 것을 만들어 오겠다.

profile
Flutter Programmer (github: RGLie)

0개의 댓글