Flutter에서의 커스텀 애니메이션 적용하기
Flutter에서는 애니메이션을 쉽게 구현할 수 있도록 다양한 도구를 제공합니다. 기본적으로 AnimatedContainer나 AnimatedOpacity 같은 내장 위젯을 사용할 수도 있지만, 더 정교한 애니메이션을 만들기 위해서는 AnimationController, Tween, CustomPainter 등을 활용한 커스텀 애니메이션이 필요합니다.
이번 글에서는 Flutter에서 커스텀 애니메이션을 구현하는 방법을 단계별로 설명하고, 실전에서 자주 활용할 수 있는 예제들을 소개하겠습니다.
1. 애니메이션의 기본 개념
Flutter에서 애니메이션은 시간의 흐름에 따라 UI의 속성을 변경하는 것을 의미합니다. 주요 개념은 다음과 같습니다:
- Animation: 시간의 흐름에 따라 값이 변하는 객체
- AnimationController: 애니메이션을 시작, 중지, 되감기 등의 제어하는 컨트롤러
- Tween: 애니메이션의 시작값과 끝값을 설정하는 보간기
- Curves: 애니메이션의 속도 곡선을 정의하는 클래스 (e.g., Curves.easeInOut)
- Ticker: 애니메이션을 프레임 단위로 실행하도록 하는 타이밍 메커니즘
Flutter에서 애니메이션을 구현하는 가장 기본적인 방법은 AnimationController와 Tween을 사용하는 것입니다.
2. AnimationController를 활용한 기본 애니메이션
AnimationController는 애니메이션의 진행 상태를 직접 제어할 수 있는 컨트롤러입니다.
예제: 크기가 커졌다 작아지는 애니메이션
import 'package:flutter/material.dart';
class ScaleAnimation extends StatefulWidget {
@override
_ScaleAnimationState createState() => _ScaleAnimationState();
}
class _ScaleAnimationState extends State<ScaleAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)..repeat(reverse: true);
_animation = Tween<double>(begin: 1.0, end: 1.5).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Transform.scale(
scale: _animation.value,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
);
},
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
이 코드에서는 AnimationController와 Tween을 이용해 크기가 1.0에서 1.5까지 변하는 애니메이션을 구현했습니다.
3. TweenSequence를 활용한 다단계 애니메이션
여러 개의 트윈을 조합하여 복합적인 애니메이션을 만들 수도 있습니다.
예제: 크기가 점진적으로 변하는 애니메이션
_animation = TweenSequence([
TweenSequenceItem(tween: Tween(begin: 1.0, end: 1.2), weight: 50),
TweenSequenceItem(tween: Tween(begin: 1.2, end: 0.8), weight: 50),
TweenSequenceItem(tween: Tween(begin: 0.8, end: 1.0), weight: 50),
]).animate(_controller);
위 코드는 크기가 1.0 → 1.2 → 0.8 → 1.0 순서로 변화하는 애니메이션을 구현합니다.
4. CustomPainter를 활용한 커스텀 애니메이션
CustomPainter를 사용하면 더욱 자유로운 애니메이션을 만들 수 있습니다.
예제: 원이 점점 커지는 애니메이션
class CirclePainter extends CustomPainter {
final double radius;
CirclePainter(this.radius);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
canvas.drawCircle(size.center(Offset.zero), radius, paint);
}
@override
bool shouldRepaint(CirclePainter oldDelegate) => oldDelegate.radius != radius;
}
이제 AnimationController를 사용해 radius 값을 애니메이션으로 조정할 수 있습니다.
class CircleAnimation extends StatefulWidget {
@override
_CircleAnimationState createState() => _CircleAnimationState();
}
class _CircleAnimationState extends State<CircleAnimation> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _radiusAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 2))..repeat(reverse: true);
_radiusAnimation = Tween<double>(begin: 10.0, end: 50.0).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimatedBuilder(
animation: _radiusAnimation,
builder: (context, child) {
return CustomPaint(
size: Size(100, 100),
painter: CirclePainter(_radiusAnimation.value),
);
},
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
5. 결론
Flutter에서는 AnimationController, Tween, CustomPainter 등을 활용하여 강력한 커스텀 애니메이션을 구현할 수 있습니다.
- AnimationController: 애니메이션의 타이밍을 제어
- Tween: 값의 보간을 담당
- Curves: 자연스러운 애니메이션 효과 추가
- CustomPainter: 복잡한 UI 애니메이션 구현 가능
Flutter에서 애니메이션을 효과적으로 활용하면 UX를 크게 향상시킬 수 있습니다.
앞으로 프로젝트에서 애니메이션을 적극적으로 활용해보시기 바랍니다.
'Flutter' 카테고리의 다른 글
Flutter에서의 Composite 패턴 적용하기 (0) | 2025.03.05 |
---|---|
Flutter 메모리 누수 방지 전략 (0) | 2025.03.02 |
Flutter 프로젝트 폴더 구조 가이드 (0) | 2025.02.28 |
Flutter Dialog(팝업) 종류 정리 (0) | 2025.02.24 |
Flutter에서 스레드 처리: 효율적인 비동기 프로그래밍 (0) | 2025.02.19 |