动画简介
FLutter中的动画分为两类:补间(tween)动画和基于物理的动画
注意Duration(动画持续的时间)的单位是毫秒,2000毫秒就是2秒。
bounch弹簧效果 ease抖动效果
注意animate()返回的是一个Animation,而不是一个Animatable
代码(一) 字体变大动画
class MMM extends StatefulWidget {
const MMM({Key? key}) : super(key: key);
@override
State<MMM> createState() => _MMMState();
}
class _MMMState extends State<MMM> with SingleTickerProviderStateMixin {
late Animation<double> tween;
late AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 4000), vsync: this);
tween = Tween(begin: 0.0, end: 1.0).animate(controller)
..addListener(() {
setState(() {
print(tween.value);
});
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('动画'),
),
body: GestureDetector(
onTap: () {
setState(() {
controller.forward(from: 0.0);
});
},
child: Center(
child: Text(
'字体放大',
style: TextStyle(fontSize: 60 * controller.value),
),
),
),
);
}
}
代码二 缓动动画
Curveds.fastOutSlowIn 快出慢进
AnimatedBuilder是一个中间件,将Animation和要作用的Widget关联起来。
class MMM extends StatefulWidget {
const MMM({Key? key}) : super(key: key);
@override
State<MMM> createState() => _MMMState();
}
class _MMMState extends State<MMM> with SingleTickerProviderStateMixin {
late Animation animation; //这里不指定泛型
late AnimationController controller;
// 定义时函数类型可以省略 (不建议省略)
//在 dart 里,被省略的函数返回值不是 void,dart 可以允许你不写函数的返回值,编译器会自动帮助你返回 null
handler(status) {
if (status == AnimationStatus.completed) {//监听动画完成状态
animation.removeStatusListener(handler);//移除监听
controller.reset();//重置controller
animation = Tween(begin: 0.0, end: 1.0).animate(
//使用非线性动画,也就是所谓的插值器,Tween是估值器
CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn))
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
print("两个动画都执行完了");
}
});
controller.forward();//执行第二个动画
}
}
@override
void initState() {
super.initState();
controller =
AnimationController(duration: const Duration(seconds: 4), vsync: this);
animation = Tween(begin: -1.0, end: 0.0).animate(
//使用非线性动画,也就是所谓的插值器,Tween是估值器
CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn))
..addStatusListener(handler);
}
@override
Widget build(BuildContext context) {
//计算屏幕的宽度
final double width = MediaQuery.of(context).size.width;
controller.forward();
return Scaffold(
appBar: AppBar(
title: const Text('动画'),
),
body: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Transform(//矩阵转换的方式移动控件
transform:
//参数是x,y,z
Matrix4.translationValues(animation.value * width, 0, 0),
//矩阵包裹的内容
child: Center(
child: Container(
width: 200.0,
height: 200.0,
color: Colors.green,
),
),
);
},
));
}
@override
void dispose() {
super.dispose();
//销毁动画
controller.dispose();
}
}
代码三遮罩动画
一个容器遮住另一个容器,使用动画叠加
import 'package:flutter/material.dart';
class MaskAnimation extends StatefulWidget {
_MaskAnimation createState() => _MaskAnimation();
}
class _MaskAnimation extends State<MaskAnimation> with SingleTickerProviderStateMixin {
AnimationController _controller;
//需要两个补间对象
Animation<double> transitionTween;
Animation<BorderRadius> borderRadius;//给BorderRadius做补间
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: const Duration(seconds: 10),)
..addStatusListener((status){//针对controller做监听
if(status == AnimationStatus.completed){
Navigator.pop(context);
}
});
transitionTween = Tween<double>(begin: 50,end: 200).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.ease//
),
);
//一种特殊的tween
borderRadius = BorderRadiusTween(
begin: BorderRadius.circular(75.0),
end: BorderRadius.circular(0.0),
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.ease
),
);
_controller.forward();
}
@override
Widget build(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
_controller.forward();
//AnimatedBuilder放到最外围
return AnimatedBuilder(
animation: _controller,
builder: (context,child){
return Scaffold(
appBar: AppBar(
title: Text('遮罩动画'),
),
body: Center(
child: Stack(//放上下两层
children: <Widget>[
Center(
child: Container(
width: 200.0,
height: 200.0,
color: Colors.black12,
),
),
Center(
child: Container(
alignment: Alignment.bottomCenter,
width: transitionTween.value,
height:transitionTween.value,
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: borderRadius.value,
),
),
),
],
),
),
);
});
}
@override
void dispose(){
_controller.dispose();
super.dispose();
}
}
代码三 数字值变化
import 'package:flutter/material.dart';
class ValueAnimation extends StatefulWidget {
_ValueAnimation createState() => _ValueAnimation();
}
class _ValueAnimation extends State<ValueAnimation> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation animation;
@override
void initState() {
super.initState();
controller = AnimationController(vsync: this, duration: const Duration(seconds: 10),);
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut);
animation = IntTween(begin: 0,end: 10).animate(curve)..addStatusListener((status){
if(status == AnimationStatus.completed){
controller.reverse();//完成后反转
}
if(status == AnimationStatus.dismissed){
Navigator.pop(context);
}
});
}
@override
Widget build(BuildContext context) {
controller.forward();
return AnimatedBuilder(
animation: controller,
builder: (context,child){
return Scaffold(
appBar: AppBar(
title: Text('数字变化动画'),
),
body: Center(
child: Text(animation.value.toString(),style: TextStyle(fontSize: 48.0),),
),
);
});
}
@override
void dispose(){
controller.dispose();
super.dispose();
}
}
代码4图表动画
import 'package:flutter/material.dart';
class ChartsAnimation extends StatefulWidget {
_ChartsAnimation createState() => _ChartsAnimation();
}
//不需要with了,因为我们使用了AnimatedContainer,不是自定义
class _ChartsAnimation extends State<ChartsAnimation>{
var height = 100.0;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('图表动画'),
),
body: Center(
child: Container(
height: 400,
//放在底部
alignment: AlignmentDirectional.bottomStart,
//InkWell带有点击效果
child: InkWell(
onTap: (){
setState(() {
height = 320;
});
},
//放柱状图
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedContainer(
duration: Duration(seconds: 1),
width: 40.0,
height: height - 40,
color: Colors.greenAccent,
),
AnimatedContainer(
margin: EdgeInsets.only(left: 10.0),
duration: Duration(seconds: 2),
width: 40.0,
height: height - 10,
color: Colors.yellow,
),
AnimatedContainer(
margin: EdgeInsets.only(left: 10.0),
duration: Duration(seconds: 3),
width: 40.0,
height: height - 60,
color: Colors.red,
),
AnimatedContainer(
margin: EdgeInsets.only(left: 10.0),
duration: Duration(seconds: 2),
width: 40.0,
height: height - 50,
color: Colors.blue,
),
],
),
),
),
),
);
}
}
代码5 渐隐渐显的动画效果
import 'package:flutter/material.dart';
class OpacityAnimation extends StatefulWidget {
_OpacityAnimation createState() => _OpacityAnimation();
}
class _OpacityAnimation extends State<OpacityAnimation> {
bool _visible = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('淡入淡出动画'),
),
body: Center(
child: AnimatedOpacity(
opacity: _visible ? 1.0 : 0.0,//显示与隐藏,中间的过渡效果由AnimatedOpacity控制。
duration: Duration(milliseconds: 1000),
child: Container(
width: 300.0,
height: 300.0,
color: Colors.deepPurple,
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(
() {
_visible = !_visible;
},
);
},
tooltip: '显示隐藏',
child: Icon(Icons.add),
),
);
}
}
页面切换动画效果
import 'package:flutter/material.dart';
class HeroAnimation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('页面切换动画图一'),
),
body: GestureDetector(
child: Hero(//使用Hero包裹
tag: '第一张图片',
child: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1541753399410&di=05760e1c65686b018cf28d440a6ddf5c&imgtype=0&src=http%3A%2F%2Fimg1.cache.netease.com%2Fcatchpic%2FD%2FD7%2FD7D7640C07A00D831EFD2AC270ED7FA7.jpg",
),
),
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (_){
return DesinationPage();
}));
},
),
);
}
}
class DesinationPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('页面切换动画图二'),
),
body: GestureDetector(
child: Hero(
tag: '第二张图片',
child: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1541753302014&di=9edfe992f8b9d395134fd977dbfeab28&imgtype=0&src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F2f738bd4b31c870143a3a1dc2c7f9e2f0708fff7.jpg",
),
),
onTap: (){
Navigator.pop(context);
},
),
);
}
}