일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Dreamhack
- DART
- Stream
- BAEKJOON
- MATLAB
- Kaggle
- Image Processing
- C++
- study book
- 영상처리
- Computer Architecture
- system hacking
- fastapi를 사용한 파이썬 웹 개발
- PCA
- BOF
- ML
- llm을 활용 단어장 앱 개발일지
- Got
- pytorch
- Flutter
- FastAPI
- Widget
- 백준
- bloc
- ARM
- Algorithm
- rao
- BFS
- MDP
- 파이토치 트랜스포머를 활용한 자연어 처리와 컴퓨터비전 심층학습
- Today
- Total
Bull
[Flutter::Animation] implicits animations (ImplicitlyAnimatedWidget) 본문
[Flutter::Animation] implicits animations (ImplicitlyAnimatedWidget)
Bull_ 2024. 7. 24. 07:29implicts animations란?
implicits animations은 암시적 애니메이션으로 그대로 해석해보면 애니메이션을 암시해줍니다. 그 말은 애니메이션을 넌지시 알려준다는 의미가 되겠네요. 개념을 쉽게 이해하기 위해서 이 위젯을 사용하면 어떤 동작이 일어나면 애니메이션을 진행시켜줘 라고 생각해도 무방할 것 같습니다.
공식 문서의 정의된 내용을 보면 "암시적 애니메이션을 사용하면 위젯 속성을 애니메이션화할 수 있으며, 대상 값이 변경될 때마다 위젯이 이전 값에서 새 값으로 속성을 애니메이션화합니다. 이러한 방식으로 암시적 애니메이션은 편리하게 제어권을 교환하여 애니메이션 효과를 관리합니다." 라고 나와 있습니다. 즉 컨트롤러에 의해 관리될 필요없이 제한적인 상황에서 특정 프로퍼티의 변화에만 반응하는 애니메이션을 만들고 싶으면 이 implicits animations을 동작해주는 Widget을 사용하면 한결 더 간결하고 간편한 코드로 관리할 수 있겠습니다.
종류
ImplicitlyAnimatedWidget의 공식 문서를 참고해보면 어떤 ImplicitlyAnimatedWidget
의 나오는 지 확인할 수 있는데요, 하나하나 살펴보겠습니다.
참고로 ImplicitlyAnimatedWidget는 실제 Widget의 Class 명칭을 나타내고 implicits animations는 개념을 나타내는 용어이니 혼동에 유의바랍니다.
TweenAnimationBuilder
: Tween의 변화에 따른 애니메이션을 변화시켜줍니다.AnimatedAlign
: Align(정렬) 프로퍼티의 변화에 따른 애니메이션을 변화시켜줍니다.AnimatedContainer
: Container의 여러 프로퍼티(색상, 크기, 정렬 등)의 변화에 따른 애니메이션을 적용합니다. 다중 프로퍼티에 반응하고 싶은 게 목적일 때 사용합니다.AnimatedDefaultTextStyle:
TextStyle(텍스트 스타일)의 변화에 따른 애니메이션을 적용합니다.AnimatedScale
: Transform.scale(크기 조정)의 변화에 따른 애니메이션을 적용합니다.AnimatedRotation
: Transform.rotate(회전)의 변화에 따른 애니메이션을 적용합니다.AnimatedSlide
: 위젯의 위치를 정상 위치에 상대적으로 애니메이션합니다.AnimatedOpacity
: Opacity(불투명도)의 변화에 따른 애니메이션을 적용합니다.AnimatedPadding
: Padding(패딩)의 변화에 따른 애니메이션을 적용합니다.AnimatedPhysicalModel
: PhysicalModel(물리적 모델)의 변화에 따른 애니메이션을 적용합니다.AnimatedPositioned
: Positioned(위치)의 변화에 따른 애니메이션을 적용합니다.AnimatedPositionedDirectional
: PositionedDirectional(위치, 방향성)의 변화에 따른 애니메이션을 적용합니다.AnimatedTheme
: Theme(테마)의 변화에 따른 애니메이션을 적용합니다.AnimatedCrossFade
: 두 자식 위젯 사이를 크로스 페이드하며 애니메이션합니다.AnimatedSize
: 주어진 기간 동안 크기 변화를 애니메이션합니다.AnimatedSwitcher
: 하나의 위젯에서 다른 위젯으로 페이드 전환하며 애니메이션합니다.
예제
그냥 보면 모를 수도 있으니 예제를 스윽 보면서 이해해보겠습니다.
TweenAnimationBuilder
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('TweenAnimationBuilder Example')),
body: Center(child: TweenAnimationBuilderDemo()),
),
);
}
}
class TweenAnimationBuilderDemo extends StatefulWidget {
@override
_TweenAnimationBuilderDemoState createState() => _TweenAnimationBuilderDemoState();
}
class _TweenAnimationBuilderDemoState extends State<TweenAnimationBuilderDemo> {
bool _isRed = true;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_isRed = !_isRed;
});
},
child: TweenAnimationBuilder(
tween: ColorTween(begin: Colors.red, end: _isRed ? Colors.red : Colors.blue),
duration: Duration(seconds: 1),
builder: (context, Color? color, child) {
return ColorFiltered(
colorFilter: ColorFilter.mode(color!, BlendMode.modulate),
child: Container(
width: 100,
height: 100,
color: color,
),
);
},
),
);
}
}
setState
를 통해서 _isRed의 값 상태를 관리합니다. tween
프로퍼티는 _isRed의 상태에 따른 begin과 end의 값을 정해줍니다. 이로 인해 TweenAnimationBuilder
는 tween
을 관측하기 때문에 tween
의 프로퍼티가 변경됨에 따라 애니메이션의 동작을 나타낼 수 있게 됩니다.
AnimatedAlign
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedAlign Example')),
body: Center(child: AnimatedAlignDemo()),
),
);
}
}
class AnimatedAlignDemo extends StatefulWidget {
@override
_AnimatedAlignDemoState createState() => _AnimatedAlignDemoState();
}
class _AnimatedAlignDemoState extends State<AnimatedAlignDemo> {
bool _isTopLeft = true;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_isTopLeft = !_isTopLeft;
});
},
child: Container(
width: 250,
height: 250,
color: Colors.blue[50],
child: AnimatedAlign(
alignment: _isTopLeft ? Alignment.topLeft : Alignment.bottomRight,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
child: FlutterLogo(size: 50),
),
),
);
}
}
setState
를 통해 _isTopLeft의 상태를 관리합니다. alignment
프로퍼티의 _isTopLeft 상태에 따른 정렬을 표현하고 GestureDetector
를 통해 top-left에 위치하다가 클릭하면 bottom-right로 정렬됩니다. AnimatedAlign
는 alignment
을 관측하기 때문에 alignment
의 프로퍼티가 변경됨에 따라 애니메이션의 동작을 나타낼 수 있게 됩니다. 애니메이션이 없다면 어떤 효과도 없이 바로 바뀌게 되겠지만 애니메이션의 curve
를 통해 부드럽게 프레임단위로 위치가 변하는 것에 차이를 느낄 수 있습니다.
AnimatedContainer
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedContainer Example')),
body: Center(child: AnimatedContainerDemo()),
),
);
}
}
class AnimatedContainerDemo extends StatefulWidget {
@override
_AnimatedContainerDemoState createState() => _AnimatedContainerDemoState();
}
class _AnimatedContainerDemoState extends State<AnimatedContainerDemo> {
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
child: AnimatedContainer(
width: _isExpanded ? 200.0 : 100.0,
height: _isExpanded ? 200.0 : 100.0,
color: _isExpanded ? Colors.blue : Colors.red,
alignment: _isExpanded ? Alignment.center : AlignmentDirectional.topCenter,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
child: FlutterLogo(size: 75),
),
);
}
}
setState
를 통해 _isExpanded 상태를 관리합니다. width
, height
, color
, alignment
프로퍼티는 _isExpanded 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _isExpanded의 값을 바꿉니다. AnimatedContainer
는 프로퍼티 하나에 대해서만 애니메이션 효과를 주는 것이 아닌 여러 프로퍼티에 대해 애니메이션 효과를 주고 싶을 때 사용합니다. 참고로 결과에서 alignment
가 안바뀌는 거 같지만 자세히 보면 마우스 포인터 기준으로 움직이는 걸 볼 수 있고 큰 컨테이너에 대한 center와 작은 컨테이너에 대한 top-center의 위치가 비슷하기 때문에 헷갈릴 수 있는 점 참고 바랍니다.
AnimatedDefaultTextStyle
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedDefaultTextStyle Example')),
body: Center(child: AnimatedDefaultTextStyleDemo()),
),
);
}
}
class AnimatedDefaultTextStyleDemo extends StatefulWidget {
@override
_AnimatedDefaultTextStyleDemoState createState() => _AnimatedDefaultTextStyleDemoState();
}
class _AnimatedDefaultTextStyleDemoState extends State<AnimatedDefaultTextStyleDemo> {
bool _toggled = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_toggled = !_toggled;
});
},
child: AnimatedDefaultTextStyle(
style: _toggled
? TextStyle(fontSize: 40.0, color: Colors.blue, fontWeight: FontWeight.bold)
: TextStyle(fontSize: 20.0, color: Colors.red, fontWeight: FontWeight.normal),
duration: Duration(seconds: 1),
child: Text('Hello Flutter'),
),
);
}
}
setState
를 통해 _toggled 상태를 관리합니다. TextStyle
위젯은 _toggled 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _toggled 값을 바꿉니다. AnimatedDefaultTextStyle
은 위의 다른 애니메이티드 위젯처럼 TextStyle
위젯의 변화에 애니메이션 효과를 추가해줍니다.
AnimatedScale
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedScale Example')),
body: Center(child: AnimatedScaleDemo()),
),
);
}
}
class AnimatedScaleDemo extends StatefulWidget {
@override
_AnimatedScaleDemoState createState() => _AnimatedScaleDemoState();
}
class _AnimatedScaleDemoState extends State<AnimatedScaleDemo> {
bool _scaled = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_scaled = !_scaled;
});
},
child: AnimatedScale(
scale: _scaled ? 2.0 : 1.0,
duration: Duration(seconds: 1),
child: FlutterLogo(size: 100),
),
);
}
}
setState
를 통해 _scaled 상태를 관리합니다. scale
프로퍼티는 _scaled 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _scaled 값을 바꿉니다. AnimatedScale
은 위의 다른 애니메이티드 위젯처럼 scale
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다.
AnimatedRotation
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedRotation Example')),
body: Center(child: AnimatedRotationDemo()),
),
);
}
}
class AnimatedRotationDemo extends StatefulWidget {
@override
_AnimatedRotationDemoState createState() => _AnimatedRotationDemoState();
}
class _AnimatedRotationDemoState extends State<AnimatedRotationDemo> {
bool _rotated = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_rotated = !_rotated;
});
},
child: AnimatedRotation(
turns: _rotated ? 1.0 : 0.0,
duration: Duration(seconds: 1),
child: FlutterLogo(size: 100),
),
);
}
}
setState
를 통해 _rotated 상태를 관리합니다. scale
프로퍼티는 _rotated 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _rotated 값을 바꿉니다. AnimatedRotation
은 위의 다른 애니메이티드 위젯처럼 turns
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다.
AnimatedSlide
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedSlide Example')),
body: Center(child: AnimatedSlideDemo()),
),
);
}
}
class AnimatedSlideDemo extends StatefulWidget {
@override
_AnimatedSlideDemoState createState() => _AnimatedSlideDemoState();
}
class _AnimatedSlideDemoState extends State<AnimatedSlideDemo> {
bool _slided = false;
void _toggleSlide() {
setState(() {
_slided = !_slided;
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedSlide(
offset: _slided ? Offset(1.0, 0.0) : Offset(0.0, 0.0),
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
child: Container(
width: 100,
height: 100,
child: Center(
child: FlutterLogo(size: 100),
),
),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _toggleSlide,
child: Text('Toggle Slide'),
),
],
);
}
}
setState
를 통해 _slided 상태를 관리합니다. offset
프로퍼티는 _slided 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _slided 값을 바꿉니다. AnimatedSlide
은 위의 다른 애니메이티드 위젯처럼 offset
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다.
참고할 사항은 이 위젯에서는 버튼을 사용했습니다. 로고를 누르면 애니메이션이 끝나고 다시 누를 때 동작하지 않아서 원인을 알아보다가 결국 찾지 못하며 다른 방법으로 바꾼 것입니다.
AnimatedOpacity
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedOpacity Example')),
body: Center(child: AnimatedOpacityDemo()),
),
);
}
}
class AnimatedOpacityDemo extends StatefulWidget {
@override
_AnimatedOpacityDemoState createState() => _AnimatedOpacityDemoState();
}
class _AnimatedOpacityDemoState extends State<AnimatedOpacityDemo> {
bool _isVisible = true;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_isVisible = !_isVisible;
});
},
child: AnimatedOpacity(
opacity: _isVisible ? 1.0 : 0.0,
duration: Duration(seconds: 1),
child: FlutterLogo(size: 100),
),
);
}
}
setState
를 통해 _isVisible 상태를 관리합니다. opacity
프로퍼티는 _isVisible 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _isVisible의 값을 바꿉니다. AnimatedOpacity
는 위의 다른 애니메이티드 위젯처럼 opacity
프로퍼티 변화에 애니메이션 효과를 추가해줍니다.
AnimatedPadding
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedPadding Example')),
body: Center(child: AnimatedPaddingDemo()),
),
);
}
}
class AnimatedPaddingDemo extends StatefulWidget {
@override
_AnimatedPaddingDemoState createState() => _AnimatedPaddingDemoState();
}
class _AnimatedPaddingDemoState extends State<AnimatedPaddingDemo> {
bool _isPadded = false;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
width: 200,
height: 200,
child: GestureDetector(
onTap: () {
setState(() {
_isPadded = !_isPadded;
});
},
child: AnimatedPadding(
padding: _isPadded ? EdgeInsets.all(50.0) : EdgeInsets.all(10.0),
duration: Duration(milliseconds: 100),
curve: Curves.easeInOut,
child: Container(
child: FlutterLogo(size: 100),
),
),
),
);
}
}
setState
를 통해 _isPadded 상태를 관리합니다. padding
프로퍼티는 _isPadded 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _isPadded 값을 바꿉니다. AnimatedPadding
는 위의 다른 애니메이티드 위젯과 차이가 있진 않지만 예제에서는 부모 위젯으로 크기가 정해진 Container를 추가해주었는데 부모 위젯이 없으면 AnimatedPadding
의 자식 컨테이너는 크기가 자동으로 정해져서 padding
프로퍼티가 작동하지 않습니다.
AnimatedPhysicalModel
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedPhysicalModel Example')),
body: Center(child: AnimatedPhysicalModelDemo()),
),
);
}
}
class AnimatedPhysicalModelDemo extends StatefulWidget {
@override
_AnimatedPhysicalModelDemoState createState() =>
_AnimatedPhysicalModelDemoState();
}
class _AnimatedPhysicalModelDemoState extends State<AnimatedPhysicalModelDemo> {
bool _elevated = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_elevated = !_elevated;
});
},
child: AnimatedPhysicalModel(
shape: BoxShape.rectangle,
elevation: _elevated ? 100.0 : 0.0,
color: Colors.blue,
shadowColor: Colors.black,
duration: Duration(seconds: 1),
child: Container(
width: 100,
height: 100,
child: FlutterLogo(size: 75),
),
),
);
}
}
setState
를 통해 _elevated 상태를 관리합니다. elevation
프로퍼티는 _elevated 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _elevated 값을 바꿉니다. AnimatedPhysicalModel
은 위의 다른 애니메이티드 위젯처럼 elevation
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다. 참고로 borderRadius
값도 관측한다는 점 알아두시기 바랍니다.
AnimatedPositioned
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedPositioned Example')),
body: Center(child: AnimatedPositionedDemo()),
),
);
}
}
class AnimatedPositionedDemo extends StatefulWidget {
@override
_AnimatedPositionedDemoState createState() => _AnimatedPositionedDemoState();
}
class _AnimatedPositionedDemoState extends State<AnimatedPositionedDemo> {
bool _moved = false;
@override
Widget build(BuildContext context) {
return Stack(
children: [
AnimatedPositioned(
width: 100.0,
height: 100.0,
top: _moved ? 200.0 : 50.0,
left: _moved ? 200.0 : 50.0,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
child: GestureDetector(
onTap: () {
setState(() {
_moved = !_moved;
});
},
child: Container(
color: Colors.blue,
child: FlutterLogo(size: 100),
),
),
),
],
);
}
}
setState
를 통해 _moved 상태를 관리합니다. top
,left
프로퍼티는 _moved 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _moved 값을 바꿉니다. AnimatedPositioned
은 위의 다른 애니메이티드 위젯처럼 top
,left
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다. 위젯의 이름에서 알 수 있듯이 top
, left
만 아니라 right
, bottom
에도 반응합니다. 그 외 position과 관련된 프로퍼티에 대해서도 결과는 같습니다.
AnimatedPositionedDirectional
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedPositionedDirectional Example')),
body: Center(child: AnimatedPositionedDirectionalDemo()),
),
);
}
}
class AnimatedPositionedDirectionalDemo extends StatefulWidget {
@override
_AnimatedPositionedDirectionalDemoState createState() => _AnimatedPositionedDirectionalDemoState();
}
class _AnimatedPositionedDirectionalDemoState extends State<AnimatedPositionedDirectionalDemo> {
bool _moved = false;
@override
Widget build(BuildContext context) {
return Stack(
children: [
AnimatedPositionedDirectional(
width: 100.0,
height: 100.0,
top: _moved ? 200.0 : 50.0,
start: _moved ? 200.0 : 50.0,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
child: GestureDetector(
onTap: () {
setState(() {
_moved = !_moved;
});
},
child: Container(
color: Colors.blue,
child: FlutterLogo(size: 100),
),
),
),
],
);
}
}
setState
를 통해 _moved 상태를 관리합니다. top
,start
프로퍼티는 _moved 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _moved 값을 바꿉니다. AnimatedPositionedDirectional
은 위의 다른 애니메이티드 위젯처럼 top
,start
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다. AnimatedPositionedDirectional
과는 비슷하지만 차이점은 '방향성'이 추가되었습니다. 즉 start
프로퍼티에 대한 관측이 추가 되었습니다.
AnimatedTheme
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: AnimatedThemeDemo(),
);
}
}
class AnimatedThemeDemo extends StatefulWidget {
@override
_AnimatedThemeDemoState createState() => _AnimatedThemeDemoState();
}
class _AnimatedThemeDemoState extends State<AnimatedThemeDemo> {
bool _isDark = false;
void _toggleTheme() {
setState(() {
_isDark = !_isDark;
});
}
@override
Widget build(BuildContext context) {
return AnimatedTheme(
data: _isDark ? ThemeData.dark() : ThemeData.light(),
duration: Duration(seconds: 1),
child: Scaffold(
appBar: AppBar(title: Text('AnimatedTheme Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _toggleTheme,
child: Text('Toggle Theme'),
),
],
),
),
),
);
}
}
setState
를 통해 _isDark 상태를 관리합니다. data
프로퍼티는 _isDark 상태에 변화에 따라 값을 표현합니다. GestureDetector
를 통해 _isDark 값을 바꿉니다. AnimatedTheme
은 위의 다른 애니메이티드 위젯처럼 data
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다. data
프로퍼티에는 ThemeData
class를 반환하면 됩니다. 앱에서 테마색을 변경할 때 사용하면 유용할 것 같습니다.
AnimatedCrossFade
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedCrossFade Example')),
body: Center(child: AnimatedCrossFadeDemo()),
),
);
}
}
class AnimatedCrossFadeDemo extends StatefulWidget {
@override
_AnimatedCrossFadeDemoState createState() => _AnimatedCrossFadeDemoState();
}
class _AnimatedCrossFadeDemoState extends State<AnimatedCrossFadeDemo> {
bool _first = true;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_first = !_first;
});
},
child: AnimatedCrossFade(
firstChild: Container(
width: 100,
height: 100,
color: Colors.blue,
child: Center(child: Text('First')),
),
secondChild: Container(
width: 100,
height: 100,
color: Colors.red,
child: Center(child: Text('Second')),
),
crossFadeState: _first ? CrossFadeState.showFirst : CrossFadeState.showSecond,
duration: Duration(seconds: 1),
),
);
}
}
setState
를 통해 _first 상태를 관리합니다. crossFadeState
프로퍼티는 _first 상태에 참, 거짓에 따라 firstChild
프로퍼티에 있는 자식 위젯을 반환할 것인지, secondChild
프로퍼티에 있는 자식 위젯을 반환할 것인지 나타낼 수 있습니다. GestureDetector
를 통해 _first 값을 바꿉니다. AnimatedCrossFade
의 특징은 이름에 걸맞게 애니메이션 효과를 부여하면서 두 자식 위젯이 교차하며 사라집니다.
AnimatedSize
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedSize Example')),
body: Center(child: AnimatedSizeDemo()),
),
);
}
}
class AnimatedSizeDemo extends StatefulWidget {
@override
_AnimatedSizeDemoState createState() => _AnimatedSizeDemoState();
}
class _AnimatedSizeDemoState extends State<AnimatedSizeDemo>
with SingleTickerProviderStateMixin {
bool _large = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_large = !_large;
});
},
child: Center(
child: AnimatedSize(
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
child: Container(
alignment: Alignment.center,
child: FlutterLogo(size: _large ? 200.0 : 100.0),
),
),
),
);
}
}
setState
를 통해 _large 상태를 관리합니다. size
프로퍼티는 _large 상태에 변화에 따라 값을 표현합니다.
GestureDetector
를 통해 _large 값을 바꿉니다. AnimatedSize
은 위의 다른 애니메이티드 위젯처럼 size
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다.
AnimatedSwitcher
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('AnimatedSwitcher Example')),
body: Center(child: AnimatedSwitcherDemo()),
),
);
}
}
class AnimatedSwitcherDemo extends StatefulWidget {
@override
_AnimatedSwitcherDemoState createState() => _AnimatedSwitcherDemoState();
}
class _AnimatedSwitcherDemoState extends State<AnimatedSwitcherDemo> {
bool _toggled = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_toggled = !_toggled;
});
},
child: AnimatedSwitcher(
duration: Duration(seconds: 1),
child: _toggled
? Container(
key: ValueKey(1),
width: 100,
height: 100,
color: Colors.blue,
child: Center(child: Text('First')),
)
: Container(
key: ValueKey(2),
width: 100,
height: 100,
color: Colors.red,
child: Center(child: Text('Second')),
),
),
);
}
}
setState
를 통해 _toggled 상태를 관리합니다. child
위젯으로 AnimatedCrossFade
와 같은 방식을 구현할 수 있습니다. GestureDetector
를 통해 _toggled 값을 바꿉니다. AnimateSwither
은 위의 다른 애니메이티드 위젯처럼 size
프로퍼티의 변화에 애니메이션 효과를 추가해줍니다.
참고 자료
'Software Framework > Flutter' 카테고리의 다른 글
[Flutter::Animation] Hero 기법 (1) | 2024.07.25 |
---|---|
[Flutter::Animation] Fade 기법 (1) | 2024.07.25 |
[Flutter::Animation] Ticker 이해 (0) | 2024.07.23 |
[Flutter::Animation] Tween 예제를 쓰면서 이해해보자 (3) | 2024.07.23 |
[Flutter::Widget] Flutter에서 git Contributions Graph(잔디밭)을 만들어 보자. (0) | 2024.07.17 |