Android Flutter实现GIF动画效果的方法详解
(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun)
前言
我们之前介绍了不少有关动画的篇章。前面介绍的动画都是只有一个动画效果,那如果我们想对某个组件实现一组动效,比如下面的效果,该怎么办?
staggered animation
这个时候我们需要用到组合动效, Flutter 提供了交错动画(Staggered Animation)的方式实现。对于多个 Anmation
对象,可以共用一个 AnimationController
,然后在不同的时间段执行动画效果。这就有点像 GIF 图片一样,一帧帧图像播放实现连续的动画。
交错动画机制
交错动画的实现基于以下几个要点:
- 所有的 animation对象使用同一个
AnimationController
驱动; - 不管实际动画持续的时间长度多长,动画控制器
controller
的值必须在0-1之间; - 每个动画对象都有一个0-1范围内的间隔(
Interval
); - 在间隔时间内,
Tween
对象从起始值过渡到结束值。 - 由
AnimationController
统一管理这些Tween 产生的Animation
对象。
听起来有点抽象,我们以一张图来表述就清晰多了,假设我们有4个动画对象,分别控制组件的透明度(Opacity
),宽度(Width
),高度(Height
)和颜色(Color
),交错动画过程如下:
时序示意图
controller
是一个从0到1的归一化的动画控制,其实对应的就是动画时长的归一化。然后 Opacity
透明度动效占据了0-0.25区间;Width
占据了0.25-0.5区间;Height
占据了0.5-0.75区间;最后是 Color
占据了0.75-1.0的区间。区间对应就是动画的时间间隔,只是每个区间内的Tween
动画对象的取值范围都是0-1以控制从起始值到结束值。我们可以理解为是 AnimationController
将多个 Animation
对象按序(也可以重合)拼接起来形成复合形式的动画。
代码实现
看上面的说明是不是觉得还有些难以理解,我们来一段示例代码就很容易明白了。下面的代码我们定义了一个共用的_controller
,然后四段动画对象_opaticy
,_width
,_height
和_color
。其中关键的实现是使用了 Tween
对象的 animate
方法,并指定了一个 CurvedAnimation
对象作为 其parent
参数。而这个CurvedAnimation
实际使用 Interval
来切分_controller
的动画时间,从而可以将多个 Animation
对象组合起来。
import?'package:flutter/material.dart'; class?StaggeredAnimationDemo?extends?StatefulWidget?{ ??StaggeredAnimationDemo({Key??key})?:?super(key:?key); ??@override ??_StaggeredAnimationDemoState?createState()?=>?_StaggeredAnimationDemoState(); } class?_StaggeredAnimationDemoState?extends?State<StaggeredAnimationDemo> ????with?SingleTickerProviderStateMixin?{ ??late?AnimationController?_controller; ??late?Animation<double>?_opacity; ??late?Animation<double>?_width; ??late?Animation<double>?_height; ??late?Animation<Color?>?_color; ??@override ??void?initState()?{ ????_controller?= ????????AnimationController(duration:?Duration(seconds:?2),?vsync:?this) ??????????..addListener(()?{ ????????????setState(()?{}); ??????????}); ????_opacity?=?Tween<double>(begin:?0.5,?end:?1.0).animate( ??????CurvedAnimation( ????????parent:?_controller, ????????curve:?Interval( ??????????0.0, ??????????0.25, ??????????curve:?Curves.easeIn, ????????), ??????), ????); ????_width?=?Tween<double>(begin:?0.0,?end:?2.0).animate( ??????CurvedAnimation( ????????parent:?_controller, ????????curve:?Interval( ??????????0.25, ??????????0.5, ??????????curve:?Curves.easeIn, ????????), ??????), ????); ????_height?=?Tween<double>(begin:?0.0,?end:?2.0).animate( ??????CurvedAnimation( ????????parent:?_controller, ????????curve:?Interval( ??????????0.5, ??????????0.75, ??????????curve:?Curves.easeIn, ????????), ??????), ????); ????_color?=?ColorTween(begin:?Colors.green,?end:?Colors.blue).animate( ??????CurvedAnimation( ????????parent:?_controller, ????????curve:?Interval( ??????????0.75, ??????????1.0, ??????????curve:?Curves.easeIn, ????????), ??????), ????); ????super.initState(); ??} ??@override ??Widget?build(BuildContext?context)?{ ????return?Scaffold( ??????appBar:?AppBar( ????????title:?const?Text('交错动画'), ??????), ??????body:?Center( ????????child:?Opacity( ??????????opacity:?_opacity.value, ??????????child:?Container( ????????????width:?100?+?100?*?_width.value, ????????????height:?100?+?100?*?_height.value, ????????????color:?_color.value, ??????????), ????????), ??????), ??????floatingActionButton:?FloatingActionButton( ????????child:?Icon(Icons.play_arrow), ????????onPressed:?()?{ ??????????if?(_controller.isCompleted)?{ ??????????????_controller.reverse(); ????????????}?else?if?(!_controller.isAnimating)?{ ??????????????_controller.forward(); ??????????} ????????}, ??????), ????); ??} }
我们来看一下运行效果,可以看到运行的动画过程其实就是4段动画效果拼接来的,先是透明度改变,然后是宽度改变,再之后是高度改变,最后是颜色的改变。
运行效果
Interval 介绍
我们来看一下关键的 Interval
类的介绍。
A curve that is 0.0 until [begin], then curved (according to [curve]) from 0.0 at [begin] to 1.0 at [end], then remains 1.0 past [end].
Interval
类继承自 Curve
,所不同的是,在 begin
之前曲线的值一直保持为0.0,而在 end
之后一直保持为1.0。所以可以理解为,在 AnimationController
启动动画后,Interval
曲线其实也已经在绘制,只是有效的取值区间只在 begin
到 end
之间,下面就是 Interval
的一种示例曲线图。
image.png
从 Interval
的源码也能看出来,其中 clamp
方法限制了取值范围,当 t <= begin
的时候取值就是0,当 t >= end
的时候,取值就是1.0。
@override double?transformInternal(double?t)?{ ??assert(begin?>=?0.0); ??assert(begin?<=?1.0); ??assert(end?>=?0.0); ??assert(end?<=?1.0); ??assert(end?>=?begin); ??t?=?((t?-?begin)?/?(end?-?begin)).clamp(0.0,?1.0); ??if?(t?==?0.0?||?t?==?1.0) ????return?t; ??return?curve.transform(t); }
总结
本篇介绍了交错动画的实现机制和示例,通过交错动画给了我们更多动效组合的空间,从而可以实现类似 GIF图片的那种多帧组合在一起的动画效果。
到此这篇关于Android Flutter实现GIF动画效果的方法详解的文章就介绍到这了,更多相关Android Flutter GIF动画效果内容请搜索程序员之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持程序员之家!
相关文章
Android项目实战手把手教你画圆形水波纹loadingview
这篇文章主要为大家详细介绍了Android项目实战手把手教你画圆形水波纹loadingview,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2016-01-01Android Studio报错Manifest merger failed with multiple errors
这篇文章主要介绍了Android Studio报错Manifest merger failed with multiple errors2017-10-10Kotlin 协程 supervisorScope {} 运行崩溃解决方法
看过很多?supervisorScope {}?文档的使用,我照抄一摸一样的代码,运行就崩溃,最后找到了解决方法,应该是kotlin版本更新做过改动,当前我使用的是?androidx.core:core-ktx:1.9.0,本文给大家介绍Kotlin 协程 supervisorScope {} 运行崩溃解决方法,感兴趣的朋友一起看看吧2024-01-01Android TextView实现带链接文字事件监听的三种常用方式示例
这篇文章主要介绍了Android TextView实现带链接文字事件监听的方法,结合实例形式分析了链接跳转、setMovementMethod及布局属性设置三种常用的实现方式,需要的朋友可以参考下2017-08-08
最新评论