实现原理
- 动画就是动起来得画面
- 视觉暂留: 画面经视神经传入大脑后,不会立即消失(会保留一段时间)
- 帧: 单个得画面,在学术上叫帧。每秒中展示得帧数简称为
fps
(Frame per Second)
动画分类
-
补间动画
在补间动画中我们定义开始点和结束点、 时间线以及定义转换时间和速度曲线,然后由系统计算, 从开始运动到结束点、 从而形成动画效果
例如:从透明度度0 到 1, 从颜色值 0 到 255
-
拟物动画
模拟动画是对真是世界得行为进行建模,是动画效果类似与现时中得物理效果。
例如: 弹簧、重力、抛物线。。。。。
动画
AnimationController
在指定的时间内, 将组件属性值由初始值演变成终止值,从而形成动画效果。
属性 | 类型 | 说明 |
---|---|---|
duration | Duration | 动画的执行时间 |
reverseDuration | Duration | 动画反向执行时间 |
lowerBound | 0.0 | lowerBound = 0.0 表示动画最小值 |
upperBound | 1.0 | upperBound= 1.0 表示动画最大值 |
value | lowerBound 、 upperBound | 动画初始值,默认是lowerBound |
vsync | TickerProvider | 防止动画(动画页面切换到后台时)消耗不必要资源 |
动画状态
AnimationStatus.dismissed
- 动画初始化状态AnimationStatus.completed
- 动画结束状态AnimationStatus.forward
- 动画处在从开始到结束的运行状态AnimationStatus.reverse
- 动画处在从结束到开始的运行状态
AnimationController 控制动画的方法
AnimationController.forward()
可以正向执行动画AnimationController.reverse()
可以反向执行动画AnimationController.dispose()
用来释放动画资源(在不适用时调用此方法,否则会造成资源泄露)AnimationController.stop()
用来停止动画运行
使用步骤
-
创建动画
controller = AnimationController(duration, vsync)
-
创建动画曲线
动画曲线(CurvedAnimation) 补间动画 (Tween)
-
监听动画曲线
addListener() // 监听动画生成值 addStatusListener() // 监听动画状态
-
执行动画
controller.forward() // 正向执行 controller.reverse() // 反向执行
-
组件销毁时移除动画
@override void dispose() { // TODO: implement dispose super.dispose(); controller.dispose(); }
代码示例
import 'package:flutter/material.dart';
class Body extends StatefulWidget {
Body({Key key}) : super(key: key);
@override
_BodyState createState() => _BodyState();
}
// 注意,使用动画时必须混入SingleTickerProviderStateMixin 类
class _BodyState extends State<Body> with SingleTickerProviderStateMixin{
AnimationController controller;
Animation animation;
@override
void initState() {
super.initState();
// 1. 创建controller;
controller = AnimationController(
// 设置动画时长
duration: Duration(
milliseconds: 1000,
),
// 固定写法
vsync: this,
);
// 2. 设置动画曲线
animation = CurvedAnimation(
curve: Curves.bounceIn, // 曲线
parent: controller, // 动画曲线作用与某个动画
);
// 2.1 设置动画值得范围, 添加到controller 中, 注意这里时double 类型
animation = Tween(begin: 20.0, end: 100.0).animate(controller);
// 3.监听曲线变化
animation.addListener((){
print(animation.value);
// 必须声明setState, 不然无法刷新组件
setState(() {});
});
// 4.执行动画
// controller.forward(); // 正向执行
}
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Icon(
Icons.accessible_rounded,
color: Colors.red,
size: animation.value
),
ElevatedButton(
onPressed: () {
// 4.执行动画
controller.forward();
},
child: Text('放大'),
),
ElevatedButton(
onPressed: () {
// 4.执行动画
controller.reverse();
},
child: Text('缩小'),
),
ElevatedButton(
onPressed: () {
// 4.执行动画
controller.stop();
},
child: Text('停止'),
),
ElevatedButton(
onPressed: () {
// 监听动画状态
animation.addStatusListener((state) {
// 判断动画状态
if (state == AnimationStatus.dismissed) {
controller.forward();
}
if (state == AnimationStatus.completed) {
controller.reverse();
}
});
controller.forward();
},
child: Text('重复执行'),
),
],
),
);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
controller.dispose();
}
}
交织动画
交织动画是由多个单一动画叠加而成复杂动画
需要给每个动画设置时间间隔
import 'package:flutter/material.dart';
import 'dart:math';
class Body extends StatefulWidget {
Body({Key key}) : super(key: key);
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<Body> with SingleTickerProviderStateMixin{
AnimationController controller;
Animation animation;
Animation sizeAnimation;
Animation colorAnimation;
Animation rotateAnimation;
@override
void initState() {
super.initState();
// 创建动画
controller = AnimationController(
duration: Duration(seconds: 3),
vsync: this,
);
// 创建动画曲线
animation = CurvedAnimation(
curve: Interval(0.0, 0.5),
parent: controller,
)..addListener(() {
setState((){});
});
sizeAnimation = Tween(begin:0.0, end:50.0).animate(animation);
colorAnimation = ColorTween(begin: Colors.yellow, end: Colors.pink).animate(
CurvedAnimation(
curve: Interval(0.5, 0.8),
parent: controller,
)
);
rotateAnimation = Tween(begin: 0.0, end: 2*pi).animate(CurvedAnimation(
curve: Interval(0.8, 1.0),
parent: controller,
)
);
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
Opacity(
opacity: controller.value,
child: Transform.rotate(
angle: rotateAnimation.value,
child: Container(
width: sizeAnimation.value,
height: sizeAnimation.value,
color: colorAnimation.value,
)
)
),
ElevatedButton(
onPressed: () {
// 4.执行动画
controller.forward();
},
child: Text('放大'),
),
ElevatedButton(
onPressed: () {
// 4.执行动画
controller.reverse();
},
child: Text('缩小'),
),
ElevatedButton(
onPressed: () {
// 4.执行动画
controller.stop();
},
child: Text('停止'),
),
]
),
);
}
}
Hero 动画
Hero 动画用来实现跨页面的动画效果
在不同的页面中,声明一个共享组件,由于共享组件在不同页面中的位置,外观等不同,切换路由时,形成动画效果
实现思路
-
在A页面中定义初始Hero 组件(source hero), 声明tag
-
在B 页面中定义目标Hero 组件 (destination hero), 绑定相同tag
-
页面跳转时,通过Navigator, 传递tag
tag路由切换时,共享组件的标记