1. AnimationController
动画控制器,控制动画的启动、停止,还可以获取动画的运行状态
class _AnimationDemoState extends State
with SingleTickerProviderStateMixin 创建一个AnimationController
AnimationController(vsync:this, duration:Duration(seconds:3))
vsync:本身Widget(单个 AnimationController 的时候使用 SingleTickerProviderStateMixin,多个 AnimationController 使用 TickerProviderStateMixin), 存在vsync时会防止屏幕外动画消耗不必要的资源
动画的状态分为四种:
dismissed:动画停止在开始处。
forward:动画正在从开始处运行到结束处(正向运行)。
reverse:动画正在从结束处运行到开始处(反向运行)。
completed:动画停止在结束处。
动画的控制方法:
forward:正向执行动画。
reverse:反向执行动画。
repeat:反复执行动画。
reset:重置动画。
使用示例
监听页面状态变化
_animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_animationController.reset();
setState(() {
_islike =false;
});
}
});
_animationController?.addListener(() {
// 页面刷新
setState(() {
});
});
_animationController.value 默认值值是从0-1的
AnimationController销毁
void dispose() {
super.dispose();
_animationController?.dispose();
}
2.Tween 和 Curve
把从 0 -> 1 转换为 蓝色 -> 红色 行为称之为 Tween(映射),
Curve Tween的值之间变化的规律(线性...)
系统提供的 Tween(选中类Tween,快捷键Ctrol+h,查看类的继承关系)
系统已经提供了38种常用到动画曲线 Curves.bounceIn
使用示例
ColorTween(begin: Colors.blue, end: Colors.red)
.chain(CurveTween(curve: Curves.bounceIn))
.animate(_animationController!)
另外一种使用方式
_animationController?.drive(CurveTween(curve: Curves.linear))
.drive(Tween(begin:100.0, end:200.0));
自定义curve
class MyCurve extends Curve {
@override
double transformInternal(double t) {
return t; //线性执行
}
}
需要继承 Curve 重写 transformInternal 方法
3.组合动画
实现 40%,widget由 100 -> 200, 20% widget大小保持不变, 40%widget 背景色由蓝色-> 红色
_tweenSequenceAnimation =TweenSequence([
TweenSequenceItem(tween:Tween(begin:100.0, end:200.0), weight:40),
TweenSequenceItem(tween:ConstantTween(200.0), weight:20),
TweenSequenceItem(tween:ColorTween(begin: Colors.blue, end: Colors.red), weight:40),
]).animate(_animationController!);
TweenSequence 值使用
width:_tweenSequenceAnimation?.value is double ?_tweenSequenceAnimation?.value :200,
height:_tweenSequenceAnimation?.value is double ?_tweenSequenceAnimation?.value :200,
color:_tweenSequenceAnimation?.value is Color ?_tweenSequenceAnimation?.value : Colors.blue
4.隐性动画和显性动画
显性动画:动画组件只封装 setState 方法
隐性动画:组件封装了 AnimationController、Curve、Tween
显性动画系统的类
隐性动画系统的类
使用示例 见下面路由动画
5.路由动画
自定义动画 需要实现PageRouteBuilder
自定义从左往右动画
class LeftToRightPageRouteextends PageRouteBuilder {
final Widget_newpage;
LeftToRightPageRoute(this._newpage)
:super(pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return _newpage;
}, transitionsBuilder: (BuildContext context,
Animation animation,
Animation secondaryAnimation,
Widget child) {
return SlideTransition(
position:Tween(begin:Offset(1,0), end:Offset(0,0))
.animate(animation),
child: child,
);
});
}
// 页面圆形形状 打开
class CirclePageRouteextends PageRouteBuilder {
final Widget_newpage;
CirclePageRoute(this._newpage)
:super(pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return _newpage;
}, transitionsBuilder: (BuildContext context,
Animation animation,
Animation secondaryAnimation,
Widget child) {
return AnimatedBuilder(
animation: animation,
builder: (context, child) {
return ClipPath(
clipper:_CustomClip(animation.value),
child: child,
);
},
child: child,
);
});
}
自定义裁剪形状
class _CustomClipextends CustomClipper {
final doublevalue;
_CustomClip(this.value);
@override
Path getClip(Size size) {
Path _path =Path();
double radius = value * sqrt(size.height * size.height + size.width * size.width);
_path.addOval(Rect.fromCircle(center:Offset(size.width,0), radius: radius));
return _path;
}
@override
bool shouldReclip(covariant CustomClipper oldClipper) {
return true;
}
}
6.其他动画
Hero 动画,系统提供的动画插件animations: ^1.1.1(使用参考官方文档)
Flow(
delegate:CirclePointFlowDelegate(),
children: [
_buildCirclePoint(2,Color(0xFF97B1CE), circleAnimation), // 自定义的组件,circleAnimation Animation
],
)
class CirclePointFlowDelegateextends FlowDelegate {
@override
void paintChildren(FlowPaintingContext context) {
print(context.size);
double radius =30;
double rx = context.size.width /2;
double ry = context.size.height /2;
for (int i =0;i < context.childCount;i++) {
print(context.getChildSize(i));
if (i %2 ==0) {
double x = rx + (radius) * cos(i *2 * pi / (context.childCount -1));
double y = ry + (radius) * sin(i *2 * pi / (context.childCount -1));
context.paintChild(i, transform:Matrix4.translationValues(x, y,0));
}else {
double x = rx + (radius ) * cos((i -1) *2 * pi / (context.childCount -1) + 2 * pi / ((context.childCount -1) *3));
double y = ry + (radius) * sin((i -1) *2 * pi / (context.childCount -1) + 2 * pi / ((context.childCount -1) *3));
context.paintChild(i, transform:Matrix4.translationValues(x, y,0));
}
}
}
@override
bool shouldRepaint(covariant FlowDelegate oldDelegate) {
return true;
}
}