https://api.flutter.dev/flutter/animation/Curves-class.html
페이지 이동할 때 애니메이션을 적용하기 위해 Hero 위젯을 이용한다. Hero 위젯은 페이지 간 이미지를 자연스럽게 애니메이션으로 연결해준다.
환경 준비
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- images/circle.png
- images/saturn.png
- images/sunny.png
코드
- people.dart
class People {
late String name;
late double height;
late double weight;
late double bmi;
People(this.name, this.height, this.weight) {
this.bmi = weight / ((height / 100) * (weight / 100));
}
}
- main.dart
import 'package:animation_example/introPage.dart';
import 'package:animation_example/people.dart';
import 'package:flutter/material.dart';
import 'SecondPage.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: IntroPage(),
);
}
}
class AnimationApp extends StatefulWidget {
@override
State<AnimationApp> createState() => _AnimationApp();
}
class _AnimationApp extends State<AnimationApp> {
List<People> peoples = [
People('스미스', 180, 92),
People('메리', 162, 55),
People('존', 177, 75),
People('바트', 130, 40),
People('콘', 194, 140),
People('디디', 100, 80),
];
Color weightColor = Colors.blue;
int current = 0;
double _opacity = 1;
@override
void initState() {
super.initState();
}
void _changeWeightColor(double weight) {
weightColor = weight < 40
? Colors.blueAccent
: weight < 60
? Colors.indigo
: weight < 80
? Colors.orange
: Colors.red;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
children: [
Icon(Icons.info),
Text('Animation Example'),
],
mainAxisAlignment: MainAxisAlignment.start,
),
),
body: Container(
child: Center(
child: Column(
children: [
AnimatedOpacity(
opacity: _opacity,
duration: Duration(seconds: 1),
curve: Curves.easeIn,
child: SizedBox(
child: Row(
children: [
SizedBox(
width: 100,
child: Text('이름 ${peoples[current].name}'),
),
AnimatedContainer(
duration: Duration(milliseconds: 800),
curve: Curves.easeIn,
color: Colors.amber,
child: Text(
'키 ${peoples[current].height}',
textAlign: TextAlign.center,
),
width: 50,
height: peoples[current].height,
),
AnimatedContainer(
duration: Duration(milliseconds: 800),
curve: Curves.easeInCubic,
color: weightColor,
child: Text(
'몸무게 ${peoples[current].weight}',
textAlign: TextAlign.center,
),
width: 50,
height: peoples[current].weight,
),
AnimatedContainer(
duration: Duration(milliseconds: 800),
curve: Curves.linear,
color: Colors.pinkAccent,
child: Text(
'bmi ${peoples[current].bmi}',
textAlign: TextAlign.center,
),
width: 50,
height: peoples[current].bmi,
),
],
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.end,
),
height: 200,
),
),
ElevatedButton(
onPressed: () {
setState(() {
current = (current + 1) % (peoples.length);
_changeWeightColor(peoples[current].weight);
});
},
child: Text('다음'),
),
ElevatedButton(
onPressed: () {
setState(() {
current =
(current + peoples.length - 1) % (peoples.length);
_changeWeightColor(peoples[current].weight);
});
},
child: Text('이전')
),
ElevatedButton(
onPressed: () {
setState(() {
_opacity == 1 ? _opacity = 0 : _opacity = 1;
});
},
child: Text('사라지기'),
),
ElevatedButton(
onPressed:() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPage()
)
);
},
child: SizedBox(
width: 200,
child: Row(
children: [
Hero(tag: 'detail', child: Icon(Icons.cake)),
Text('이동하기'),
],
),
),
)
],
mainAxisAlignment: MainAxisAlignment.center,
),
),
),
);
}
}
- introPage.dart
import 'dart:async';
import 'package:animation_example/SaturnLoading.dart';
import 'package:animation_example/main.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class IntroPage extends StatefulWidget {
@override
State<IntroPage> createState() => _IntroPage();
}
class _IntroPage extends State<IntroPage> {
Future<Timer> loadData() async {
return Timer(Duration(seconds: 5), () async {
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (context) => AnimationApp()));
});
}
@override
void initState() {
super.initState();
loadData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Column(
children: [
Text('애니메이션 앱'),
SizedBox(
height: 20,
),
SaturnLoading(),
],
mainAxisAlignment: MainAxisAlignment.center,
),
),
),
);
}
}
- SaturnLoading.dart
import 'dart:math';
import 'package:flutter/cupertino.dart';
class SaturnLoading extends StatefulWidget {
_SaturnLoading _saturnLoading = _SaturnLoading();
void start() {
_saturnLoading.start();
}
void stop() {
_saturnLoading.stop();
}
@override
State<StatefulWidget> createState() => _saturnLoading;
}
class _SaturnLoading extends State<SaturnLoading>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation _animation;
void start() {
_animationController.repeat();
}
void stop() {
_animationController.stop(canceled: true);
}
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: Duration(seconds: 3));
_animation =
Tween<double>(begin: 0, end: pi * 2).animate(_animationController);
_animationController.repeat();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return SizedBox(
width: 100,
height: 100,
child: Stack(
children: [
Image.asset(
'images/circle.png',
width: 100,
height: 100,
),
Center(
child: Image.asset(
'images/sunny.png',
width: 30,
height: 30,
),
),
Padding(
padding: EdgeInsets.all(5),
child: Transform.rotate(
angle: _animation.value,
origin: Offset(35, 35),
child: Image.asset(
'images/saturn.png',
width: 20,
height: 20,
),
),
),
],
),
);
});
}
}
- SecondPage.dart
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SecondPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _SecondPage();
}
class _SecondPage extends State<SecondPage>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation _rotateAnimation;
late Animation _scaleAnimation;
late Animation _transAnimation;
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: Duration(seconds: 5));
_rotateAnimation =
Tween<double>(begin: 0, end: pi * 10).animate(_animationController);
_scaleAnimation =
Tween<double>(begin: 1, end: 0).animate(_animationController);
_transAnimation = Tween<Offset>(begin: Offset(0, 0), end: Offset(200, 200))
.animate(_animationController);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Animation Example2')),
body: Container(
child: Center(
child: Column(
children: [
AnimatedBuilder(
animation: _rotateAnimation,
builder: (context, widget) {
return Transform.translate(
offset: _transAnimation.value,
child: Transform.rotate(
angle: _rotateAnimation.value,
child: Transform.scale(
scale: _scaleAnimation.value,
child: widget,
),
),
);
},
child: Hero(
tag: 'detail',
child: Icon(
Icons.cake,
size: 300,
)),
),
ElevatedButton(
onPressed: () {
_animationController.forward();
},
child: Text('로테이션 시작하기'))
],
mainAxisAlignment: MainAxisAlignment.center,
),
),
),
);
}
}
Uploaded by Notion2Tistory v1.1.0