개발노트

61. [Flutter] AnimatedBuilder 명시적인 애니메이션 위젯이 없을 때 사용하기 (with Tween, AnimationController) 본문

앱 개발/Flutter

61. [Flutter] AnimatedBuilder 명시적인 애니메이션 위젯이 없을 때 사용하기 (with Tween, AnimationController)

mroh1226 2024. 1. 31. 11:00
반응형

AnimatedBuilder

AnimatedBuilder는 애니메이션을 지속적으로 업데이트하면서 UI를 리빌드할 때 사용됩니다.

이 위젯은 애니메이션의 값이 변경될 때마다 특정한 위젯을 다시 그려주기 때문에 애니메이션의 효과를 적용하는 데 매우 효율적입니다.

여기서 **AnimatedBuilder**의 주요 요소를 살펴보겠습니다:

  1. animation 매개변수:animation 매개변수는 Animation 객체를 받습니다. 이 Animation 객체는 주로 **AnimationController**를 통해 제어되는 애니메이션입니다. **AnimatedBuilder**는 이 애니메이션의 값이 변경될 때마다 자동으로 다시 빌드됩니다.
  2. builder 콜백 함수:builder 콜백 함수는 애니메이션 값이 변경될 때마다 호출되며, 새로운 위젯을 반환합니다. 일반적으로 이 함수 안에서 UI를 구성하는 위젯을 반환합니다. builder 함수는 다음 매개변수를 받습니다:
    • BuildContext context: 현재 위젯의 빌드 문맥을 나타내는 객체입니다.
    • Widget? child: 이전 빌드에서 생성된 위젯입니다. **AnimatedBuilder**를 사용하여 구현할 때 필요한 경우가 아니면 무시해도 됩니다.

이제 **AnimatedBuilder**의 장점을 살펴보겠습니다:

  • 성능 향상: **AnimatedBuilder**를 사용하면 애니메이션의 일부분만 다시 그려지므로 전체 위젯 트리를 다시 빌드할 필요가 없어서 성능이 향상됩니다.
  • 모듈화: **AnimatedBuilder**를 사용하면 UI의 일부를 분리하여 재사용할 수 있습니다. 특히 애니메이션을 적용하는 부분을 모듈화하여 코드를 더 깔끔하게 유지할 수 있습니다.
  • 가독성 향상: builder 함수 안에 UI를 구성하는 코드가 명시적으로 나타나므로 가독성이 향상됩니다.

AnimationBuilder 사용 예시

예시 소스.
import 'package:flutter/material.dart';

class ExplicitAnimationScreen extends StatefulWidget {
  const ExplicitAnimationScreen({super.key});
  static String routeName = "explicitanimation";
  static String routeURL = "explicitanimation";

  @override
  State<ExplicitAnimationScreen> createState() =>
      _ExplicitAnimationScreenState();
}

class _ExplicitAnimationScreenState extends State<ExplicitAnimationScreen>
//SingleTickerProviderStateMixin -> Ticker가 하나만 필요할 때
//TickerProviderStateMixin -> Ticker가 여러개 필요할 떄
    with
        SingleTickerProviderStateMixin {
  late final AnimationController _animationController = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 2000),
    //lowerBound: 50,      upperBound: 100
  );

  late final Animation<Color?> _color =
      ColorTween(begin: Colors.amber, end: Colors.blue)
          .animate(_animationController);

  late final Animation<Decoration> _decoration = DecorationTween(
          begin: const BoxDecoration(color: Colors.amber),
          end: const BoxDecoration(color: Colors.red))
      .animate(_animationController);

  @override
  void initState() {
    _animationController.addListener(() {});
    _animationController.addStatusListener((status) {});	//status: 애니메이션 forward,reverse,pause,complete 등 상태를 
    super.initState();
    // //Ticker는 애니메이션 프레임 하나당 한번 호출됨
    // Ticker((elapsed) {
    //   print(elapsed);
    // });
  }

  void _play() {
    _animationController.forward();
  }

  void _pause() {
    _animationController.stop();
  }

  void _reverse() {
    _animationController.reverse();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        title: const Text("Explicit Animations"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            //AnimatedBuilder를 사용하면 화면 전체가 빌드되지않고 builder안에 있는 위젯만 리빌드됨
            AnimatedBuilder(
              animation: _animationController,
              builder: (context, child) {
                return Text("${_animationController.value}");
              },
            ),
            AnimatedBuilder(
              animation: _color,
              builder: (context, child) {
                return Container(
                  color: _color.value,
                  width: 100,
                  height: 100,
                );
              },
            ),
            AnimatedBuilder(
              animation: _decoration,
              builder: (context, child) {
                return Container(
                  height: 100,
                  width: 100,
                  decoration: _decoration.value,
                );
              },
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                ElevatedButton(onPressed: _play, child: const Text("Play")),
                ElevatedButton(onPressed: _pause, child: const Text("pause")),
                ElevatedButton(
                    onPressed: _reverse, child: const Text("reverse")),
              ],
            )
          ],
        ),
      ),
    );
  }
}

예시 소스 설명.

애니메이션 구성 요소:

1. ColorTween: _animationController를 생성하여 애니메이션을 제어합니다. 이 애니메이션 컨트롤러는 애니메이션의 시간을 2초로 설정하고, vsync에 this를 전달하여 Ticker를 제공합니다.

late final Animation<Color?> _color = 
		ColorTween(begin: Colors.amber, end: Colors.blue).animate(_animationController);

 

2. DecorationTween:  DecorationTween은 Flutter에서 애니메이션을 적용할 때 사용되는 클래스 중 하나로, 애니메이션 기간 동안 BoxDecoration의 속성을 변경하는 데 사용됩니다. 이를 통해 위젯의 배경색, 테두리, 그림자 등과 같은 장식을 부드럽게 전환할 수 있습니다. 

  late final Animation<Decoration> _decoration = DecorationTween(
          begin: const BoxDecoration(color: Colors.amber),
          end: const BoxDecoration(color: Colors.red))
      .animate(_animationController);

*Tween: begin 상태에서 end 상태로 변환됨

 

3. AnimationController 생성: _color, _decoration 애니메이션은 _animationController에 의해 제어됩니다.
vsync에 Ticker를 설정하고, duration에 애니메이션 실행 시간을 설정 해줍니다.

late final AnimationController _animationController = 
	AnimationController( vsync: this, duration: const Duration(milliseconds: 2000), );

 

4. AnimationController  초기화 및 Listener :

위젯이 생성될 때 _animationController에 대한 초기화 작업을 수행하고 Listener를 추가합니다.

@override void initState() { 
    _animationController.addListener(() {}); 
    _animationController.addStateusListener(status{});
    super.initState(); 
    }

 

.addStateusListener(status{}) 로 애니메이션 상태를 Listen 할 수 있으며, 데이터 타입은 AnimationStatus 로 사용가능합니다.

상태에는 아래와 같이 완료, 실패, 순방향, 역방향 이 있습니다. 이를 이용한 조건문을 작성하여 loop를 돌리거나 여러 동작을 만들 수 있습니다.

 

.addStateusListener(status{})  사용 예시.

. addStateusListener ( status {}) 사용 예시


AnimatedBuilder 위젯 사용 소스.

 

1. AnimationController.value를 연결한 AnimatedBuilder:

AnimatedBuilder( animation: _animationController, 
	builder: (context, child) { 
		return Text("${_animationController.value}"); 
    }, 
  ),

 

2. ColorTween.value 를 연결한 AnimatedBuilder:

AnimatedBuilder( animation: _color, 
	builder: (context, child) { 
		return Container( color: _color.value, width: 100, height: 100, ); 
    }, 
  ),

 

3 .DecorationTween.value 연결한 AnimatedBuilder

 AnimatedBuilder(
              animation: _decoration,
              builder: (context, child) {
                return Container(
                  height: 100,
                  width: 100,
                  decoration: _decoration.value,
                );
              },
            ),
반응형
Comments