Flutter에서 애니메이션은 UI의 동적 변화를 매끄럽고 시각적으로 매력적으로 만드는 데 매우 중요한 역할을 합니다. 애니메이션을 통해 사용자 경험을 향상시키고, 사용자 인터페이스를 더 직관적으로 만들 수 있습니다. 이 글에서는 Flutter 애니메이션의 기본 개념부터 고급 기능까지 쉽게 설명하겠습니다.
1. Flutter 애니메이션 개요
Flutter에서 애니메이션은 일반적으로 Animation
과 AnimationController
를 중심으로 구성됩니다. 기본적으로 Flutter 애니메이션은 다음과 같은 요소로 이루어져 있습니다:
Animation
: 애니메이션의 값이 시간에 따라 어떻게 변하는지를 정의합니다.AnimationController
: 애니메이션의 상태를 관리하며, 애니메이션의 시작, 정지 및 제어를 담당합니다.Tween
: 애니메이션이 시작과 끝 사이의 값 변화를 정의합니다.AnimatedWidget
: 애니메이션의 상태를 위젯에 적용하는 역할을 합니다.AnimationBuilder
: 애니메이션의 값에 따라 위젯을 동적으로 변경하는 데 사용됩니다.
2. 기본 애니메이션
2.1. FadeTransition (투명도 애니메이션)
FadeTransition
을 사용하면 위젯의 투명도를 애니메이션으로 변경할 수 있습니다.
예제 코드:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FadeTransitionDemo(),
);
}
}
class FadeTransitionDemo extends StatefulWidget {
@override
_FadeTransitionDemoState createState() => _FadeTransitionDemoState();
}
class _FadeTransitionDemoState extends State<FadeTransitionDemo> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Fade Transition Demo')),
body: Center(
child: FadeTransition(
opacity: _animation,
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
2.2. SlideTransition (슬라이딩 애니메이션)
SlideTransition
을 사용하면 위젯이 화면의 특정 방향으로 슬라이드하도록 애니메이션을 적용할 수 있습니다.
예제 코드:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SlideTransitionDemo(),
);
}
}
class SlideTransitionDemo extends StatefulWidget {
@override
_SlideTransitionDemoState createState() => _SlideTransitionDemoState();
}
class _SlideTransitionDemoState extends State<SlideTransitionDemo> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Offset> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_animation = Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset.zero).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Slide Transition Demo')),
body: Center(
child: SlideTransition(
position: _animation,
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
3. 고급 애니메이션
3.1. AnimatedBuilder (애니메이션 빌더)
AnimatedBuilder
를 사용하면 애니메이션의 상태를 기반으로 여러 위젯을 동적으로 업데이트할 수 있습니다.
예제 코드:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: AnimatedBuilderDemo(),
);
}
}
class AnimatedBuilderDemo extends StatefulWidget {
@override
_AnimatedBuilderDemoState createState() => _AnimatedBuilderDemoState();
}
class _AnimatedBuilderDemoState extends State<AnimatedBuilderDemo> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_animation = Tween<double>(begin: 0.0, end: 100.0).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('AnimatedBuilder Demo')),
body: Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
color: Colors.green,
);
},
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
3.2. AnimatedWidget (애니메이션 위젯)
AnimatedWidget
을 사용하면 애니메이션 상태를 관리하며 위젯의 속성을 애니메이션 값에 따라 업데이트할 수 있습니다.
예제 코드:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: AnimatedWidgetDemo(),
);
}
}
class AnimatedWidgetDemo extends StatefulWidget {
@override
_AnimatedWidgetDemoState createState() => _AnimatedWidgetDemoState();
}
class _AnimatedWidgetDemoState extends State<AnimatedWidgetDemo> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_animation = Tween<double>(begin: 0.0, end: 100.0).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('AnimatedWidget Demo')),
body: Center(
child: MyAnimatedBox(animation: _animation),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
class MyAnimatedBox extends AnimatedWidget {
MyAnimatedBox({required Animation<double> animation}) : super(listenable: animation);
@override
Widget build(BuildContext context) {
final animation = listenable as Animation<double>;
return Container(
width: animation.value,
height: animation.value,
color: Colors.blue,
);
}
}
4. 애니메이션의 상태 관리
Flutter에서 애니메이션 상태를 관리하기 위해 다양한 방법을 사용할 수 있습니다. 기본적으로 AnimationController
를 사용하여 애니메이션의 상태를 제어할 수 있습니다. AnimationController
는 애니메이션의 재생, 정지, 속도 조절 등을 관리합니다.
AnimationController 설정
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
}
duration
: 애니메이션의 전체 지속 시간을 설정합니다.vsync
: 애니메이션의 동기화를 처리하는TickerProvider
를 지정합니다.
애니메이션 제어
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true); // 애니메이션을 반복하며 역방향으로 재생
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
repeat()
: 애니메이션을 반복합니다.dispose()
: 애니메이션이 더 이상 필요하지 않을 때 메모리 누수를 방지하기 위해dispose
메서드에서 컨트