본문 바로가기
Flutter

[flutter] 애니메이션

by 개발짜 2024. 12. 19.

Flutter 의 애니메이션에서는 크게 암시적 애니메이션과 명시적 애니메이션으로 구분된다.

 

암시적 애니메이션(Implict Animations)

- 개발자가 세부 동작을 구현하지 않아도 위젯에서 임의로 애니메이션 효과가 나타난다.

 

애니메이션 위젯 참고

Animated~ 로 붙어있는 위젯은 애니메이션이 제공되는 위젯이다.

 

자주 사용할 위젯 예시

AnimatedAlign

GestureDetector(
  onTap: () {
    setState(() {
      selected = !selected;
    });
  },
  child: Container(
    height: 300,
    width: double.infinity,
    color: Colors.blue,
    child: AnimatedAlign(
      // alignment 속성이 변경되면 애니메이션 진행이 됨
      alignment: selected ? Alignment.topLeft : Alignment.bottomRight,
      curve: Curves.easeIn, // 애니메이션 효과
      duration: Duration(seconds: 5), // 애니메이션이 진행되는 시간
      child: Container(
        width: 50,
        height: 50,
        color: Colors.red,
      ),
    ),
  ),
);

 

 

AnimatedContainer

GestureDetector(
  onTap: () {
    setState(() {
      selected = !selected;
    });
  },
  child: Container(
    height: 300,
    width: double.infinity,
    color: Colors.purple,
    // 바깥 컨테이너에서 alignment 속성이 주어지지 않으면 내부의 container 가 다 덮어씌워짐
    alignment: Alignment.center,
    child: AnimatedContainer(
      // 속성 값 변경되면 애니메이션 진행(alignment, height, width, decoration 등)
      alignment: selected ? Alignment.topLeft : Alignment.bottomRight,
      height: selected ? 200 : 100,
      width: selected ? 200 : 100,
      decoration: BoxDecoration(
        color: selected ? Colors.green : Colors.red,
        borderRadius: BorderRadius.circular(selected ? 20 : 0),
      ),
      curve: Curves.linear,
      duration: Duration(seconds: 2), // 애니메이션이 진행되는 시간
      child: Container(
        width: 50,
        height: 50,
        color: Colors.amber,
      ),
    ),
  ),
);

 

Hero

- 다른 화면으로 이동할 때 위젯을 연결하는 애니메이션 효과 제공 - tag 속성을 이용하여 연결을 해야한다

class HeroExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        Navigator.of(context).push(MaterialPageRoute(
          builder: (context) {
            return HeroPage();
          },
        ));
      },
      child: Container(
        child: Row(
          children: [
            Hero(
              // tag 설정
              tag: 'sample-image',
              child: SizedBox(
                width: 100,
                height: 100,
                child: Image.network(
                  'https://picsum.photos/200/200',
                  fit: BoxFit.cover,
                ),
              ),
            ),
            SizedBox(width: 10),
            Text('상품명'),
            SizedBox(width: 10),
            Text('200,0000원'),
          ],
        ),
      ),
    );
  }
}

class HeroPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: [
          Hero(
            // tag 설정
            tag: 'sample-image',
            child: AspectRatio(
              aspectRatio: 1,
              child: Image.network(
                'https://picsum.photos/200/200',
                fit: BoxFit.cover,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

 

 

 

 

명시적 애니메이션(Explicit Animations)

- 개발자가 애니메이션의 세부 동작을 모두 직접 구현하는 방식이다.

 

AnimationController 객체로 애니메이션 진행상태 제어

class ExplictExample extends StatefulWidget {
  @override
  State<ExplictExample> createState() => _ExplictExampleState();
}

class _ExplictExampleState extends State<ExplictExample>
    with TickerProviderStateMixin {
  late final animationController = AnimationController(
    vsync: this,
    duration: Duration(seconds: 10),
  );

  // 애니메이션 진행될 때 0 부터 300 까지 value 값이 증가 됨
  late final animation =
      Tween<double>(begin: 0, end: 300).animate(animationController);

  @override
  void dispose() {
    animationController.dispose(); // 메모리 소거
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      // 위젯을 꾹 눌렀을 때
      onLongPressDown: (details) {
        // 애니메이션 진행
        animationController.forward();
      },
      // 위젯을 꾹 누르고 손을 뗄 때
      onLongPressEnd: (details) {
        // 애니메이션 멈춤
        animationController.stop();
      },
      // 위젯을 꾹 누르다가 취소될 때
      onLongPressCancel: () {
        // 애니메이션 멈춤
        animationController.stop();
      },
      // 두 번 터치했을 때
      onDoubleTap: () {
        // 애니메이션 값이 초기화
        animationController.reset();
      },
      child: Container(
        width: double.infinity,
        height: 300,
        color: Colors.blue,
        alignment: Alignment.center,
        child: Stack(
          children: [
            Container(
              width: 50,
              height: 300,
              color: Colors.red,
            ),
            AnimatedBuilder(
              // animation 값이 변경될 때마다 builder 가 호출된다
              animation: animation,
              builder: (context, child) {
                return Container(
                  width: 50,
                  height: animation.value,
                  color: Colors.green,
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

 

꾹 누름(초록색 게이지 움직임) -> 마우스 뗌(초록색 게이지 멈춤) -> 마우스 두 번 클릭(초록색 게이지 초기화)

 

댓글