Flutter动画

编程入门 行业动态 更新时间:2024-10-18 01:35:04

Flutter<a href=https://www.elefans.com/category/jswz/34/1769013.html style=动画"/>

Flutter动画

Curve

 缓和曲线,即单位区间到单位区间的映射,也就是动画在某一段时间内的变化特性,缓动曲线是用来随着时间的推移调整动画的变化率,允许它们加速或者减速,而不是以恒定的速度移动.

 缓动曲线的映射当0.0必须映射到0.0上,1.0必须映射到1.0上。

 这个类是一个抽象类,下面是它的部分源码:

@immutable
abstract class Curve {const Curve();double transform(double t) {assert(t >= 0.0 && t <= 1.0);if (t == 0.0 || t == 1.0) {return t;}return transformInternal(t);}@protecteddouble transformInternal(double t) {throw UnimplementedError();}Curve get flipped => FlippedCurve(this);@overrideString toString() {return '$runtimeType';}
}

 通过上面的源码可以发现,具体的计算方法其实是在transformInternal(double t)中,但是Curve并没有实现这个方法,因此在具体使用Curve的时候都是使用它的子类或者自己继承这个类来实现想要的效果

构造方法 const Curve();

 抽象的const构造函数,这个构造函数允许子类提供const构造函数,以便可以在const表达式中使用.

字段 flipped

 返回与此曲线相反的新曲线。这对于CurvedAnimation.reverseCurve通常是有用的。

方法 double transform(double t)

 返回曲线在点t处的值,这个方法必须首先确保下面两项成立:

  • td的值必须介于0.0和1.0之间
  • t在0.0和1.0处的映射必须分别对应于0.0和1.0.

 建议子类覆盖transformInternal方法而不是这个函数,因为上面的情况已经在transform的默认实现中处理过了,它将剩余逻辑委托给transformInternal

方法 double transformInternal(double t)

 在0.0 < t < 1.0的情况下,返回曲线在点t处的值。

 演示:将之前的一个点的运动轨迹使用Curve进行处理,效果如下:

//动画速率变化CurvedAnimation _curvedAnimation;@overridevoid initState() {super.initState();//初始化动画控制器_animationController =AnimationController(duration: Duration(seconds: 3), vsync: this);//_animation = _tween.animate(_animationController);_curvedAnimation = CurvedAnimation(parent: _animationController,curve: Curves.bounceIn.flipped);_animation = _tween.animate(_curvedAnimation);_animation.addListener(() {_updatePage();});}

 最终的效果如下:

[外链图片转存失败(img-jQVhBYK0-1564037739637)( “使用Curve包装动画”)]

Animation class

 类型为T的动画,动画由一个值(类型为T)和一个状态组成,状态指示动画是在概念上从开始运行到结束还是从结束运行到开始,动画的实际值可能不会单调地变化(例如:动画使用一条反弹地曲线)。动画还允许其它对象监听其值或者状态的改变,These callbacks are called during the “animation” phase of the pipeline,就在重构widget之前。要创建一个可以向前或者向后运行的新动画,可以使用AnimationController

 源码如下:

import 'package:flutter/foundation.dart';import 'tween.dart';// Examples can assume:
// AnimationController _controller;/// The status of an animation
enum AnimationStatus {/// The animation is stopped at the beginningdismissed,/// The animation is running from beginning to endforward,/// The animation is running backwards, from end to beginningreverse,/// The animation is stopped at the endcompleted,
}typedef AnimationStatusListener = void Function(AnimationStatus status);abstract class Animation<T> extends Listenable implements ValueListenable<T> {const Animation();@overridevoid addListener(VoidCallback listener);@overridevoid removeListener(VoidCallback listener);void addStatusListener(AnimationStatusListener listener);void removeStatusListener(AnimationStatusListener listener);AnimationStatus get status;@overrideT get value;bool get isDismissed => status == AnimationStatus.dismissed;bool get isCompleted => status == AnimationStatuspleted;@optionalTypeArgsAnimation<U> drive<U>(Animatable<U> child) {assert(this is Animation<double>);return child.animate(this as dynamic); // TODO(ianh): Clean this once  is fixed.}@overrideString toString() {return '${describeIdentity(this)}(${toStringDetails()})';}String toStringDetails() {assert(status != null);String icon;switch (status) {case AnimationStatus.forward:icon = '\u25B6'; // >break;case AnimationStatus.reverse:icon = '\u25C0'; // <break;case AnimationStatuspleted:icon = '\u23ED'; // >>|break;case AnimationStatus.dismissed:icon = '\u23EE'; // |<<break;}assert(icon != null);return '$icon';}
}
属性 isCompleted -> bool

 判断是否在动画结束时停止,从源码中可以看出,当动画的状态为AnimationStatuspleted时返回true。

属性 isDismissed -> bool

 判断是否这个动画在开始位置停止。从源码可以看出,当动画状态为AnimationStatus.dismissed时返回true。

属性 AnimationStatus status

 表示动画当前的状态,返回一个美剧类型AnimationStatus中的一种状态。

属性 T value

 动画的当前值,源码中即返回T。

方法 addListener(VoidCallback listener)

 每当动画的值发生变化时调用这个监听器。添加的监听器可以通过方法removeListener移除。

方法 addStatusListener(AnimationStatusListener listener)

 每次动画状态改变的时候会调用这个监听器,可以使用removeStatusListener来移除掉添加的监听器.

方法 Animation<U> drive <U>(Animatable<U> child)

 将Tween或者CurveTween链接到此动画,但是需要注意的是:此方法仅适用于Animation实例,也就是说,它可以调用AnimationController对象,以及CurvedAnimations,ProxyAnimations,ReverseAnimations,TrainHoppingAnimations等。它返回与方法(子方法)的参数U类型相同的动画,方法(子方法)的值是通过将给定的Tween应用于该动画的值而派生出来的.

 示例一: 给定一个AnimationController _controller,下面的代码创建一个Animation<Alignment>,当控制器从0.0到1.0时,它从左上角到右上角摇摆

Animation<Alignment> _alignment1 = _controller.drive(AlignmentTween(begin: Alignment.topLeft,end: Alignment.topRight),
);

 实例二:_alignment.value可以在widgetbuild方法之后使用,例如:使用Alignment widget定位子部件,使子部件的位置从左上角移动到右上角,curve这种曲线是很常见的,例如在开始时使过渡变慢,在结束时使过渡变快,下面的代码演示了一种将前一个示例中的Tween链接到Curve(这里是Curves.easeIn)的方法,在这里,Tween是在其它地方创建的,作为一个可重用的变量,因为它的参数没有发生变化:

final Animatable<Alignment> _tween = AlignmentTween(begin:Alignment.topLeft,end:Alignment.topRight).chain(CurveTween(curve:Curves.easeIn));//...Animation<Alignment> _alignment2 = _controller.drive(_tween);

 实例三:下面的代码和上面的是完全相同的,并且使用下面这种方式在以内联方式创建渐变时更清晰,当渐变的值依赖于其它变量时,这可能是首选:

Animation<Alignment> alignment3 = _controller.drive(CurveTween(curve:Curves.easeIn)).drive(AlignmentTween(begin:Alignment.topLeft,end:Alignment.topRight,));

AnimationController class

 动画控制器.使用这个类可以执行以下任务:

  • 使用forward或者reverse播放一个动画,或者stop停止一个动画
  • 将动画设置为特定的值
  • 定义动画的上界和下界值
  • 使用物理模拟创建一个动画效果

 默认情况下,AnimationController在给定的持续时间内线性生成范围从0.0到1.0的值,每当运行应用程序的设备准备显示新帧时,动画控制器就会生成一个新值(通常,这个速度约为每秒60个值)。

  一个AnimationController需要一个TickerProvider,通过构造方法中的vsync参数进行配置。TickerProvider接口描述了一个用于Ticker对象的工厂,Ticker是一个对象,它知道如何在SchedulerBinding中注册自己,并在每一帧中触发一个回调,AnimationController类使用一个Ticker来遍历它所控制的动画。

 如果一个AnimationContrioller是在State中被创建的,那么State可以使用TickerProviderStateMixinSingleTickerProviderStateMixin类来实现TickerProvider接口,TickerProviderStateMixin类总是为此而工作,在类只需要一个Ticker的情况下(例如:如果类在整个声明周期中只创建一个AnimationController),SingleTickerProviderStateMixin效率稍微会高一点。

 当一个AnimationController不再需要的时候,应该处理掉它,这可以减稍泄露的可能性。当一个AnimationControllerStatefulWidget一起使用时,通常会在State.initState方法中创建它,然后在State.dispose方法中处理掉它。

 启动动画的方法当动画成功完成时返回一个TickerFuture对象,并且不会抛出错误,如果一个动画被取消了,那么future永远不会完成,这个对象也有一个TickerFuture.orCancel属性,该属性返回一个future,当动画成功完成时,该future会完成,当动画终止时,该future会以一个错误完成.

 演示代码如下:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';class AnimationDemo1 extends StatefulWidget {  @override_AnimationDemo1State createState() {return _AnimationDemo1State();}
}class _AnimationDemo1State extends State<AnimationDemo1>with SingleTickerProviderStateMixin {//动画Animation<Alignment> _animation;//动画控制器AnimationController _animationController;@overridevoid initState() {super.initState();_initAnimation();}//初始化动画的相关信息void _initAnimation() {_animationController = AnimationController(vsync: this,duration: Duration(seconds: 3),);_animation = _animationController.drive(CurveTween(curve: Curves.bounceIn)).drive(Tween<Alignment>(begin: Alignment.bottomCenter, end: Alignment.topCenter));_animation.addListener(() {_updatePage();});}//更新页面void _updatePage() {if (mounted) {setState(() {});}}@overrideWidget build(BuildContext context) {return Container(constraints: BoxConstraints.tightForFinite(),alignment: Alignment.bottomCenter,child: Column(children: <Widget>[Container(constraints: BoxConstraints.expand(height: 300,width: 40),alignment: _animation.value,child: Container(constraints: BoxConstraints.expand(width: 30,height: 30.0),color: Colors.redAccent,),),RaisedButton(onPressed: (){fadeOutAndUpdateState();},child: Text("点击启动动画"),)],),);}@overridevoid dispose() {if (_animationController != null) {_animationController.dispose();}super.dispose();}Future<void> fadeOutAndUpdateState() async {try {await _animationController.forward().orCancel;await _animationController.reverse().orCancel;print("动画执行结束");} on TickerCanceled {print("捕获到TickerCanceled -- 动画被取消");}}
}

 在上面的代码中,首先通过给AnimationDemo1State with SingleTickerProviderStateMixin使当前类实现了TickerProvider接口,然后定义了AnimationAnimationController对象,接着通过使用AnimationControllerdrive方法添加了TweenCurve,最后给Animation对象添加监听以改变页面进行重新绘制。同时,将启动动画的方法放在了fadeOutAndUpdateState() async中,启动动画时使用了AnimationController.forward().orCancel的方式,用以让动画在适当的时候结束。

 程序的执行顺序如下:

  1. 点击启动动画,动画会首先正向执行,同时打印" 画执行状态改变:AnimationStatus.forward"
  2. 正向执行结束后,会首先打印"动画执行状态改变:AnimationStatuspleted",然后动画会反向执行,同时打印"动画执行状态改变:AnimationStatus.reverse"
  3. 反向执行结束后,会首先打印"动画执行状态改变:AnimationStatus.dismissed",接着会打印动画执行结束
  4. 动画执行过程中结束页面,会打印"捕获到TickerCanceled – 动画被取消"

 执行过程如下所示:

 打印信息如下:

I/flutter ( 9327): 动画执行状态改变:AnimationStatus.forward
I/flutter ( 9327): 动画执行状态改变:AnimationStatuspleted
I/flutter ( 9327): 动画执行状态改变:AnimationStatus.reverse
I/flutter ( 9327): 动画执行状态改变:AnimationStatus.dismissed
I/flutter ( 9327): 动画执行结束
I/flutter ( 9327): 动画执行状态改变:AnimationStatus.forward
V/DartMessenger( 9327): Sending message with callback over channel 'flutter/keyevent'
V/DartMessenger( 9327): Sending message with callback over channel 'flutter/keyevent'
V/NavigationChannel( 9327): Sending message to pop route.
V/DartMessenger( 9327): Sending message with callback over channel 'flutter/navigation'
I/flutter ( 9327): 捕获到TickerCanceled -- 动画被取消

总结

 Flutter的动画逻辑相对来说还是比较清晰的,AnimationController用于对动画的控制,开始,结束,反向播放等,Curve用于描述动画的过程特性,加速,减速等,Animatable或者Tween及其子类用于包装需要的最终的结果类型,由于AnimationController一般是从0.0到1.0之间变化,因此在Tween中需要通过设置begin属性和end属性来进行映射。Animation就是最终得到的动画对象,通过将不同时刻Animationvalue值赋值给不同的对象来实现让对象动起来的效果。

更多推荐

Flutter动画

本文发布于:2024-02-25 03:26:14,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1697621.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:动画   Flutter

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!