Flutter动画开发:基于Tween界面和物理
UI合理的动画设计可以让用户感觉更加流畅直观,改善用户交互体验,提升用户体验。
Flutter中的动画分为两类:基于Tween的和基于物理的;
中间动画是两者之间的简称,在中间动画中定义起点,定义时间变化和速度的终点、时间点和曲线,然后系统计算如何从起点开始指向终点。
物理动画是模拟的运动,其行为就像在现实世界中一样,例如投掷物体。就像数学一样,它落地的位置取决于物体的重量、投掷速度以及物体距地面的高度。抛物线运动轨道。
简介
在Flutter中实现动画效果需要几个基本函数:Animation(动画对象)、AnimationController(动画控制器)、Tweens(插值器)、Curves(动画曲线);
1。动画
Flutter 中的动画本身与渲染用户界面无关。动画是一个抽象类,具有当前值和状态(已完成或已停止)。 Flutter 中的动画系统基于对象 Animation
。最常用的一种是动画类。它可以通过其 value 属性检索当前动画的值。除了生成双值之外,
Animation 还可以生成颜色,例如:颜色--Animation
或大小--Animation
。
动画对象可以具有监听器和状态监听器,可以使用 addListener()
和 addStatusListener()
添加。每当动画值发生变化时就会调用侦听器。我们通常在监听器中调用setState()来触发UI重建;当动画开始、结束、向前或向后移动时,会调用 StatusListener。
2。 AnimationController
AnimationController 是一个特殊的 Animation
对象,它为屏幕刷新的每一帧创建一个新值。默认情况下,AnimationController 将随时间线性生成从 0.0 到 1.0 的数字。 AnimationController 派生自 Animation
,因此它可以在需要 Animation 对象的任何地方使用。不仅如此,AnimationController还有其他方法来控制动画,比如forward()
方法来启动动画。
AnimationController({
double value,
this.duration,
this.reverseDuration,
this.debugLabel,
this.lowerBound = 0.0,
this.upperBound = 1.0,
this.animationBehavior = AnimationBehavior.normal,
@required TickerProvider vsync,
})
复制代码
创建AnimationController必须下载vsync
。传递 vsunc
可防止动画 UI 不在当前屏幕上时绘制,从而防止不必要的资源消耗。通过将 SingleTickerProviderStateMixin
混合到类定义中,您可以将状态对象用作 vsync
值。
除了vsync
还可以传递正向动画运行时间duration
和反向动画运行时间reverseDuration
等吗? 重做动画
注意:动画结束后处理控制器(调用dispose()
方法)以避免内存泄漏
@override
void dispose() {
animationController.dispose();
super.dispose();
}
复制代码
3、Tween
默认情况下, AnimationController 对象的范围从 0、0 到 1.0。如果需要不同的范围或不同的数据类型,可以使用 Tween 来配置动画以创建不同范围或数据类型的值。例如,您可以创建从 0 到 100 的数字:
final Tween doubleTween = new Tween<double>(begin: 0.0, end: 100.0);
复制代码
Tween 是一个无状态对象,它继承自 Animatable 与动画类似。它不必输出双精度值,它也可以是一种颜色,例如从白色到黑色: Tween 可以通过 animate() 方法传递控制器对象来创建动画对象。如下图 Curves用于调整动画过程中随时间变化的速率。默认情况下,动画在单个线性模型中变化。 Flutter 内部还提供了一组 Curves 对象来执行适当的变化率:linea ------ 线性、deceleration ------ 减速等。 当然,你也可以自定义一个继承曲线的类来指定动画的变化率,如: 目前,动画仅检测其自身值的变化,不会导致小部件移动。这里我们需要跟踪动画值,然后使用 setstatus 更新小部件属性以使小部件移动。 添加数值监控: 此外,我们还可以监控动画状态的变化。当动画结束时,我们反转动画。当翻转动画也结束时,我们重新启动动画以继续动画。这个循环继续下去。 状态更改侦听器: AnimatedWidget 类允许您在调用 以下代码改编自AnimatedLogo官方文档 查看 _AnimatedState源码 所谓并行动画就是几个动画一起执行。在Flutter中,您可以在同一个动画控制器上使用多个Tween,然后每个Tween处理动画中的不同效果。 ,它允许多个动画同时运行。 你可以通过 其Animatable
,而不是继承自 Animation 。补间需要两个值:开始和结束。 Tween 的唯一职责是定义输入到输出范围的映射。
添加监控final Tween colorTween = new ColorTween(begin: Colors.withe, end: Colors.black);
复制代码
AnimationController _animationController = AnimationController(animationBehavior:AnimationBehavior.normal,vsync: this);
Tween<double> _tween = Tween<double>(begin: 0.0, end: 100.0)..animate(_animationController);
复制代码
4,CurvedAnimation
class ShakeCurve extends Curve {
@override
double transform(double t) {
return math.sin(t * math.PI * 2);
}
}
复制代码
5。添加跟踪
Animation animation = CurvedAnimation(parent: _animationController, curve: Curves.linear);
animation.addListener((){
setState(() {
});
});
复制代码
animation.addStatusListener((status){
print(status);
});
复制代码
6、AnimatedWidget
setState()
时将小部件代码与动画代码分开。 AnimatedWidget不需要维护一个State对象来存储动画。import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
class AnimatedLogo extends AnimatedWidget {
AnimatedLogo({Key key, Animation<double> animation})
: super(key: key, listenable: animation);
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return new Center(
child: new Container(
margin: new EdgeInsets.symmetric(vertical: 10.0),
height: animation.value,
width: animation.value,
child: new FlutterLogo(),
),
);
}
}
class LogoApp extends StatefulWidget {
_LogoAppState createState() => new _LogoAppState();
}
class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
animation = new Tween(begin: 0.0, end: 300.0).animate(controller);
controller.forward();
}
Widget build(BuildContext context) {
return new AnimatedLogo(animation: animation);
}
dispose() {
controller.dispose();
super.dispose();
}
}
复制代码
AnimatedWidget
为什么不需要维护一个State
对象来存储动画呢? AnimatedWidget
的源码可以看到,AnimatedWidget继承于StatefulWidget
类中AnimatedWidget
创建一个有状态的小部件。_AnimatedState
,然后看类_AnimatedState
的源码部分:_AnimatedState中的
类方法initStateabstract class AnimatedWidget extends StatefulWidget{
@override
_AnimatedState createState() => _AnimatedState();
}
复制代码
_AnimatedState._handleChange
并在方法 didUpdateWidget
和 dispose
、_handleChang e
中删除其中只有一行代码,即 setState .方法:
价值。? ingleTickerProviderStateMixin 用于 TickerProviderStateMixin 。 class _AnimatedState extends State<AnimatedWidget> {
@override
void initState() {
super.initState();
// 添加监听
widget.listenable.addListener(_handleChange);
}
@override
void didUpdateWidget(AnimatedWidget oldWidget) {
super.didUpdateWidget(oldWidget);
// 移除
if (widget.listenable != oldWidget.listenable) {
oldWidget.listenable.removeListener(_handleChange);
widget.listenable.addListener(_handleChange);
}
}
@override
void dispose() {
// 移除
widget.listenable.removeListener(_handleChange);
super.dispose();
}
void _handleChange() {
// 更新状态
setState(() {
// The listenable's state is our build state, and it changed already.
});
}
@override
Widget build(BuildContext context) => widget.build(context);
}
复制代码
7.并行动画
final AnimationController controller =
new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
final Animation<double> sizeAnimation =
new Tween(begin: 0.0, end: 300.0).animate(controller);
final Animation<double> opacityAnimation =
new Tween(begin: 0.1, end: 1.0).animate(controller);
复制代码
sizeAnimation.value
获取尺寸,通过opacityAnimation.value
获取不透明度,但AnimatedWidget构造函数只接受一个动画对象。为了解决这个问题,您可以创建自己的 Tween 对象并显式计算值。 build
方法.evaluate()
调用父动画对象上的Tween函数来计算所需的size
和 不透明度
完结
作者:小风藏月
链接:https://juejin.im/post/5d8b2d36e51d4577f4608ae2
来源:掘金
版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明来源。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。