일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 깃허브
- Binding
- React JS
- Flutter
- AnimationController
- HTML
- 리엑트
- Maui
- page
- 파이어베이스
- Firebase
- 함수
- 닷넷
- 자바스크립트
- MS-SQL
- 플러터
- MVVM
- 바인딩
- JavaScript
- 애니메이션
- db
- .NET
- typescript
- listview
- spring boot
- 마우이
- Animation
- GitHub
- 오류
- MSSQL
Archives
- Today
- Total
개발노트
32. [Flutter] AnimationController 애니메이션 적용 방법 2가지 (with RotationTransition, Tween) 본문
앱 개발/Flutter
32. [Flutter] AnimationController 애니메이션 적용 방법 2가지 (with RotationTransition, Tween)
mroh1226 2023. 9. 15. 17:33반응형
AnimationController, Animation으로 애니메이션 효과 적용하기
개인적으로 노마드코더에서 Flutter를 배우면서 AnimationController, Animation 작성 방법과, 이것들을 사용하려면 왜 with SingleTickerProviderStateMixin 을 해줘야하는지 이해하기까지 어려웠습니다.
이 글에서는 AnimationController, Animation을 생성하고 애니메이션 효과를 적용하는 방법 2가지를 소개하고,
이를 AnimatedModalBarrier, SlideTransition, RotationTransition 위젯에 적용시켜보겠습니다.
구현할 애니메이션 설명
- ListTile의 속성 leading:에 들어있는 Icon을 90도 회전시키는 애니메이션을 구현
- 사용된 애니메이션 위젯: RotationTransition
첫번째 방법.
- AnimationController를 initState에 정의하고 정의된 upperBond와 loweBound를 이용하여 구현하는 방법
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class TestScreen extends StatefulWidget {
const TestScreen({super.key});
@override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen>
with SingleTickerProviderStateMixin {
late final AnimationController _animationController;
late bool _isAnimated = false;
@override
void initState() {
_animationController = AnimationController(
vsync: this,
upperBound: 0,
lowerBound: -0.25,
duration: const Duration(milliseconds: 200),
value: 0);
super.initState();
}
void _onTap() {
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_animationController.forward();
}
setState(() {
_isAnimated = !_isAnimated;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
ListTile(
onTap: _onTap,
titleAlignment: ListTileTitleAlignment.center,
contentPadding: const EdgeInsets.all(10),
title: const Text("Address"),
leading: RotationTransition(
turns: _animationController,
child: const FaIcon(FontAwesomeIcons.addressBook)),
minLeadingWidth: 10,
),
],
),
);
}
}
설명.
- RotationTransition 위젯을 회전시킬 위젯을 감싸줍니다.
- RotationTransition 의 속성 turns: 에 매핑될 AnimationController가 필수로 요구됩니다.
- late final AnimationController _animationController; //AnimationController를 정의하지않고 생성합니다.
- class _TestScreenState extends State<TestScreen>
with SingleTickerProviderStateMixin {
- 위와 같이 with 문을 사용하여 Single TickerProviderStateMixin 의 메소드와 함수들을 사용할 수 있게합니다. - void initState() {
_animationController = AnimationController(
vsync: this,
upperBound: 0,
lowerBound: -0.25,
duration: const Duration(milliseconds: 200),
value: 0);
super.initState();
}
- 생성할 때, 정의하지못한 AnimationController를 initState에 정의합니다.
- TickerProvider가 요구되는 vsync 에 with문으로 Ticker를 받은 _TestScreenState 즉, this를 매핑합니다.
- upperBound >= lowerBound가 되는 조건의 변형될 double형 값을 각각 넣습니다.
- duration:에 실행될 시간을 넣습니다.
- value:에 초기값을 넣습니다. - onTap: _onTap, 클릭했을 때 메소드 호출을 위해 onTap을 설정합니다.
- void _onTap() {
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_animationController.forward();
}
setState(() {});
}
- _animationController.isCompleted로 애니메이션 완료 상태를 확인하고 reverse(), forward()를 설정합니다.
- _animationController.reverse()는 lowerBound 에서 upperBound 수치로 변경됩니다.
- _animationController.forward()는 upperBound에서 lowerBound 수치로 변경됩니다.
- Ticker에 의해 변경되는 값들이 실시간으로 반영됩니다.
두번째 방법.
- Tween을 이용하여 begin: 시작값, end: 끝나는 값을 AnimationController에게 전달하는 방식
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class TestScreen extends StatefulWidget {
const TestScreen({super.key});
@override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen>
with SingleTickerProviderStateMixin {
late final AnimationController _animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 200));
late final Animation<double> _animation =
Tween(begin: 0.0, end: -0.25).animate(_animationController);
void _onTap() {
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_animationController.forward();
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"AnimationController, Animation",
style: TextStyle(color: Colors.black),
),
),
body: Column(
children: [
ListTile(
onTap: _onTap,
titleAlignment: ListTileTitleAlignment.center,
contentPadding: const EdgeInsets.all(10),
title: const Text("Address"),
leading: RotationTransition(
turns: _animation,
child: const FaIcon(FontAwesomeIcons.addressBook)),
minLeadingWidth: 10,
),
],
),
);
}
}
두번째 방법이 첫번째 방법과 다른점.
- 우선, 두번째방법이 첫번째 방법과 다른점은 Animation<double> 형인 Tween을 이용한다는 점입니다.
- 또한, Tween에서 begin: ,end: 값을 정의하고 animationController으로 바로 매핑하기 때문에 init에 재정의할 필요가없습니다.
- TypeScript를 해보셨다면 Generic의 개념을 알 수 있는데, Dart에서도 마찬가지로 Animation<T> = Tween(begin: T end: T) 와 같이 T는 Genric 입니다.
- 따라서 T가 예시처럼 double이 될수도있고, Color, Offset 등 다양한 값이 될 수 있습니다.
위 사항처럼 첫번째 방법과 다름점을 중점으로 설명드리겠습니다.
설명.
- late final AnimationController _animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 200));
- 생성과 동시에 vsync: , duration: 을 정의합니다. - late final Animation<double> _animation =
Tween(begin: 0.0, end: -0.25).animate(_animationController);
- turns: 속성이 double형을 받기 때문에 Animation<double> 로 생성해주고, Tween을 이용하여 begin: 시작값, end: 종료되는 값을 정의해줍니다.
- .animate(_animationController)로 컨트롤러에 Animation을 넘겨줍니다. - 첫번째 방법과 동일하게 onTap() 에 _animationController.reverse() , forward() 을 호출하여 애니메이션을 동작합니다.
서로 구현 방법은 다르지만, 구현한 기능은 동일하기 때문에 취향에 맞는 방법을 선택하여 구현하시면됩니다.
저는 니콜라스 선생님 말처럼 첫번째 방법은 AnimationController를 initState에 재정의해야하는데 이렇게하면 initState 메소드 안에 있는 다른 소스들과 섞이면서 지저분해보이기도하고, Generic을 사용할 수 있는 두번째 방법을 선택해서 구현하고 있습니다.
응용하기.
사용된 위젯:
- RotationTransition
- SlideTransition
*Animation 2개 동시 사용
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class TestScreen extends StatefulWidget {
const TestScreen({super.key});
@override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen>
with SingleTickerProviderStateMixin {
final List<String> addressList = [
"010-1234-1234",
"010-0000-0000",
"010-1111-1111",
"010-2222-2222",
"010-3333-3333",
"010-4444-4444",
"010-5555-5555",
"010-6666-6666",
"010-7777-7777",
"010-8888-8888",
"010-9999-9999",
];
late final AnimationController _animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 200));
late final Animation<double> _animationRotation =
Tween(begin: 0.0, end: -0.25).animate(_animationController);
late final Animation<Offset> _animationSlider =
Tween(begin: const Offset(-1, 0), end: const Offset(0, 0))
.animate(_animationController);
void _onTap() {
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_animationController.forward();
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"AnimationController, Animation",
style: TextStyle(color: Colors.black),
),
),
body: SingleChildScrollView(
child: Column(
children: [
ListTile(
onTap: _onTap,
titleAlignment: ListTileTitleAlignment.center,
contentPadding: const EdgeInsets.all(10),
title: const Text("Address"),
leading: RotationTransition(
turns: _animationRotation,
child: const FaIcon(FontAwesomeIcons.addressBook)),
minLeadingWidth: 10,
),
SlideTransition(
position: _animationSlider,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
for (var address in addressList)
ListTile(
title: Text(address),
)
],
),
)
],
),
),
);
}
}
반응형
'앱 개발 > Flutter' 카테고리의 다른 글
34. [Flutter] CustomScrollView 위젯 (2) | 2023.10.05 |
---|---|
33. [Flutter] AnimatedList 로 쉽게 List 애니메이션 효과 구현하기 (with GlobalKey) (0) | 2023.09.22 |
31. [Flutter] ListTile 사용하기 (with ListView) (0) | 2023.09.15 |
30. [Flutter] Dismissible 로 List item 밀어서 삭제하기 (0) | 2023.09.14 |
29. [Flutter] GridView 로 분할 화면 만들기(표 처럼) (0) | 2023.09.14 |
Comments