动画类型
动画类型:
-
补间(Tween)动画
“介于两者之间”的简称。在补间动画中,定义了开始点和结束点、时间线以及定义转换时间和速度的曲线。然后由框架计算如何从开始点过渡到结束点。
-
基于物理的动画
在基于物理的动画中,运动被模拟为与真实世界的行为相似。例如,当你掷球时,它在何处落地,取决于抛球速度有多快、球有多重、距离地面有多远。 类似地,将连接在弹簧上的球落下(并弹起)与连接到绳子上的球放下的方式也是不同。
动画常见表现形式
- 动画列表或网格
- 在网格或列表中添加或删除元素时应用动画
- 共享元素转换(Hero)
- 实现路由(页面)之间的共享元素过渡动画
- 交错动画
- 交错动画由一个动画序列或重叠的动画组成
- 一个AnimationController控制所有动画
动画库中的一些主要类
Animation
动画系统的主要构件, 接收特定类型的值,该值可以在动画的生命周期内更改。可以从该对象读取动画的当前值,并监听该值的更改。
-
addListener(VoidCallback listener)
监听Animation的值发生改变,如果要取动画当前的值,调用animation.value即可
-
addStatusListener(AnimationStatusListener listener)
监听动画的状态改变, AnimationStatus有四种状态:dismissed、forward、reverse、completed
Animation<double> _animation = Tween(begin: 0.0, end: 350.0).animate(_animationController)
..addListener(() {
this.setState(() {});
})
..addStatusListener(
(AnimationStatus status) {
if (status == AnimationStatus.dismissed) {
}...
},
);
AnimationController
创建一个动画,离不开控制器AnimationController。
- 它会产生数值 0 -- 1 区间内的数值。
- 控制动画 reverse(), forward(), animateTo(), stop() 等
- 继承Animation<double>
- 切记路由销毁时需要释放动画资源
AnimationController _animationController = AnimationController(
duration: Duration(milliseconds: _duration),
vsync: this,
);
Tween
如上面的代码, Tween接收begin和end两个参数,不仅可以是数值类型,也可以使用ColorTween, RectTween, BorderTween, AlignmentTween等接收Color, Rect, Border, Alignment等类型。
-
animate()
animate方法传入Animation<double>,返回Animation<T>类型
-
继承Animatable<T>
ColorTween _colorTween = ColorTween(
begin: Color(0xFFC1C1C1),
end: Color(0xFFC19426),
);
Curves
动画过程可以是匀速的、匀加速的或者先加速后减速等。通过Curve(曲线)来描述动画过程,我们把匀速动画称为线性的(Curves.linear), 而非匀速动画称为非线性的。
AnimationController _controller = AnimationController(
duration: Duration(milliseconds: _duration),
vsync: this,
);
Animation _curvedAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(_curvedAnimation);
Ticker
当创建AnimationController时, 需要传递一个vsync参数,它接收一个TickerProvider类型的对象,它的主要职责是创建Ticker.
通常我们使用State with SingleTickerProviderStateMixin,然后将State对象作为vsync的值。
class AnimationDialog extends StatefulWidget {
@override
AnimationDialogState createState() => AnimationDialogState();
}
class AnimationDialogState extends State<AnimationDialog>
with SingleTickerProviderStateMixin {
/// Animation Controller
AnimationController _animationController = AnimationController(
duration: Duration(milliseconds: 500),
vsync: this,
);
}
AnimatedWidget
使用Animation的时候,一般使用addListener更新当前的State
animation.addListener(() {
setState(() {
//
});
});
这就是AnimatedWidget的作用,AnimatedWidget继承StatefulWidget,并接收Listenable对象,而Animation是继承Listenable的。
使用方法:目标Widget继承AnimatedWidget,接收Animation参数。
class AnimatedLogo extends AnimatedWidget {
/// Animation
final Animation<double> animation;
AnimatedLogo({Key key, this.animation})
: super(key: key, listenable: animation);
Widget build(BuildContext context) {
return Center(
child: Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
height: animation.value,
width: animation.value,
child: FlutterLogo(),
),
);
}
}
AnimatedBuilder
在使用AnimatedWidget时,需要把目标Widget继承AnimatedWidget,这样写多少有点麻烦。如果封装一个Common类,接收animation对象和child,这就有了AnimatedWidget. Flutter中正是通过这样的方式封装了很多动画,如:FadeTransition、ScaleTransition、SizeTransition、RotationTransition等,很多时候都可以复用这些过渡类。
class GrowTransition extends StatelessWidget {
GrowTransition({this.child, this.animation});
final Widget child;
final Animation<double> animation;
Widget build(BuildContext context) {
return new Center(
child: new AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
return new Container(
height: animation.value,
width: animation.value,
child: child
);
},
child: child
),
);
}
}
Transform
Transform可以对子组件实现一些特效。
详情请参考官方介绍: book.flutterchina.club/chapter5/tr…
Container(
color: Colors.black,
child: new Transform(
alignment: Alignment.topRight, //相对于坐标系原点的对齐方式
transform: new Matrix4.skewY(0.3), //沿Y轴倾斜0.3弧度
child: new Container(
padding: const EdgeInsets.all(8.0),
color: Colors.deepOrange,
child: const Text('Apartment for rent!'),
),
),
);
-
rotate
Transform.rotate可以对子组件进行旋转变换。
-
scale
Transform.scale可以对子组件进行缩小或放大。
-
translate
Transform.translate接收一个offset参数,可以在绘制时沿x、y轴对子组件平移一定的距离。
动画示例:
卡片弹出动画对话框
实现方案:高度在持续变化的对话框
扩展:对话框可以从底部、上部、中间等位置出现。
主要代码:
Container(
height: _animation?.value ?? 0.0,
alignment: Alignment.bottomCenter,
child: SingleChildScrollView(
child: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_buildCardWidget(),
_buildBottomWidget(),
],
),
),
),
);
参考网址:
动画·《Flutter实战》:book.flutterchina.club/chapter9/an…
以上代码地址:github.com/smiling1990…