본문 바로가기
개발/Flutter

Flutter Rotate Animation (회전 애니메이션 만들기)

by 파란검정 2022. 4. 4.
반응형

Flutter Rotate Animation (회전 애니메이션 만들기)

 

위와 같은 이미지를 

아래와 같이 회전하게 만드는 방법은?? 

 

 

 

 

일정한 타이밍으로 애니메이션이 진행되어야 하는 애니메이션이

하나이기 때문에 SingleTickerProviderStateMixin 클래스를 상속받는다.

 

SingleTickerProviderStateMixin 클래스는

StatefulWidget을 지원하기 때문에 애니메이션이 구현되어야 하는 Widget은 StatefulWidget이어야한다. 

 

 

TickerProviderStateMixin을 제대로 상속받았다면 vsync 값에 this를 입력했을때 제대로 인식할 것이다. 

animationController를 선언 하면서 애니메이션의 간격을 duration 값으로 정한다.

값이 작아지면 애니메이션이 빨라진다.  

final AnimationController _animationController =
    AnimationController(vsync: this, duration: Duration(seconds: 2))..repeat();

 

 

 

 

 

AnimatedBuilder를 통해 애니메이션이 실제로 이루어 져야하는 Widget은 다음과 같은 방법으로 구현한다. 

AnimatedBuilder는 widget을 통해 생성한 animationController

실제 회전을 위한 Transform을 정의 하고 

애니메이션이 이루어져야 하는 Widget을 정의 하여 준다. 

애니메이션 동작의 on/off를 정의 하기 위해서는 angle값을 조절하면 된다. 

AnimatedBuilder(
  animation: _animationController,
  builder: (_, child) {
    return Transform.rotate(
      angle: _animationController.value * 2 * math.pi,
      child: child,
    );
  },
  child: CircleAvatar(
    radius: 40,
    backgroundImage: AssetImage('assets/img/home-delivery.png'),
  ),
)

 

 

 

위 내용을 응용하여 

Tap을 통한 animation의 on/off을 해보자면 

다음과 같이 flag값을 통해 angle값을 변경하여 

애니메이션을 on/off를 할 수 있다. 

 

GestureDetector(
  onTap: () {
    setState(() {
       isOn = !isOn;
    });
  },
  child: AnimatedBuilder(
    animation: _animationController,
    builder: (_, child) {
      return Transform.rotate(
        angle: isOn ? _animationController.value * 2 * math.pi : 0,
        child: child,
      );
    },
    child: CircleAvatar(
      radius: 40,
      backgroundImage: AssetImage('assets/img/home-delivery.png'),
    ),
  ),
);

 

 


Sample

위 내용을 적용한 sample class는 다음과 같다. 

클릭을 하면 아래와 같이 이미지의 회전이 on/off된다. 

 

 

 

 

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


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

  @override
  State<MusicRecordPlate> createState() => _MusicRecordPlateState();
}

class _MusicRecordPlateState extends State<MusicRecordPlate>
    with SingleTickerProviderStateMixin {
  bool isOn = false;
  late final AnimationController _animationController =
      AnimationController(vsync: this, duration: const Duration(seconds: 2))
        ..repeat();

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Spacer(flex: 1,),
        _getRotateRecord(),
        const Spacer(flex: 1,),
      ],
    );
  }

  Widget _getRotateRecord() {
    return GestureDetector(
      onTap: () {
        isOn = !isOn;
      },
      child: AnimatedBuilder(
        animation: _animationController,
        builder: (_, child) {
          return Transform.rotate(
            angle: isOn
                ? _animationController.value * 2 * math.pi
                : 0,
            child: child,
          );
        },
        child: const CircleAvatar(
          radius: 40,
          backgroundImage: AssetImage('assets/img/music.png'),
        ),
      ),
    );
  }
}
반응형