前言:
这是我参与8月更文挑战的第 8 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战
,我准备在本月挑选 31
个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录
的重要素材。希望可以坚持下去,你的支持将是我最大的动力~
一、认识 FadeTransition 组件
上一篇介绍了 Opacity 组件,今天来看一个可以透明动画变换的组件:
FadeTransition。其作用是:将一个
组件 以指定透明度
opacity 动画进行
透明变化`。
1.FadeTransition 基本信息
下面是 FadeTransition
组件类的定义
和 构造方法
,可以看出它继承自 SingleChildRenderObjectWidget
。实例化时必须传入 opacity
入参,其类型为 Animation<double>
,用于控制透明度的动画器。还可以传入一个 chuild
组件。
---->[FadeTransition#FadeTransition 声明]----
final Animation<double> opacity;
2.FadeTransition 的使用
FadeTransition 组件的比 Opacity
复杂很多,因为我们要指定 opacity
动画器,像这样由用户知道动画器
实现动画效果的,称之为 显示动画组件
。如下代码,是在 2S
内将透明度在 0.2 ~ 1.0
间变换的动画效果:
由于需要使用 动画器
,我们需要使用 StatefulWidget
,在 XXXState
中混入 SingleTickerProviderStateMixin
,可以让状态类作为 vsync
用来创建 AnimationController
。在 dispose
中释放动画控制器。
class FadeTransitionDemo extends StatefulWidget {
@override
_FadeTransitionDemoState createState() => _FadeTransitionDemoState();
}
class _FadeTransitionDemoState extends State<FadeTransitionDemo>
with SingleTickerProviderStateMixin {
late AnimationController _ctrl;
late Animation<double> opacityAnim;
@override
void initState() {
super.initState();
_ctrl = AnimationController(vsync: this, duration: const Duration(seconds: 2));
opacityAnim= Tween<double>(begin: 0.2,end: 1.0).animate(_ctrl);
_ctrl..forward();
}
@override
void dispose() {
_ctrl.dispose();
super.dispose();
}
通过 Tween
和 _ctrl
创建一个 0.2 ~ 1.0
的动画器 opacityAnim
, 作为入参传入 FadeTransition
构造函数中。这样在 _ctrl
动画控制器开启时,其子组件就可以执行透明度渐变动画。
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
_ctrl.forward(from: 0);
},
child: FadeTransition(
opacity: opacityAnim,
child: Image.asset(
'assets/images/icon_head.png',
width: 100,
height: 100,
),
),
);
}
二、 FadeTransition 的源码实现
1. FadeTransition 源码分析
它继承自 SingleChildRenderObjectWidget
就说明,该组件需要维护一个 RenderObject
对象的创建及更新。
在 createRenderObject
方法中,创建 RenderAnimatedOpacity
,opacity
动画器会被传入构造入参中。在 updateRenderObject
中,对 RenderAnimatedOpacity
对象进行更新。也就是说,渐变透明变换的绘制处理是在 RenderAnimatedOpacity
中进行的。
2.RenderAnimatedOpacity 源码分析
对于 FadeTransition
组件来说,最神奇的应该是:为什么透明度会跟随 Animation
对象不断触发重绘,从而进行动画。既然 动画器 opacity
是一个 Listenable
对象,那很容易想到是通过监听 动画器
进行重绘。
RenderAnimatedOpacity
通过混入 RenderAnimatedOpacityMixin
实现动画效果。
在 RenderAnimatedOpacityMixin#attach
方法中,会通过 addListener
来监听动画器的变化。在 detach
中移除监听。监听的方法是 _updateOpacity
。
在 _updateOpacity
方法中,如果新旧的 alpha
值不同,就会触发 markNeedsPaint
进行通知重绘。
在 RenderAnimatedOpacityMixin#paint
方法中的绘制逻辑和 Opacity
组件绘制是一样的。当 child
非空时,如果 _alpha = 0
就什么都不需要画,直接返回。如果 _alpha = 255
,则直接绘制 child
。
如果有透明度时,会通过 context.pushOpacity
,创建一个透明层 layer
来完成透明功能。该方法在 Opacity 组件一文中介绍过了,这里不再赘述。
3. FadeTransition 的价值
如果不知道 FadeTransition
组件的存在,我们想要实现 透明度渐变
的效果,能想到的可能就是通过 AnimatedBuilder
监听 Opacity
组件,来动态改变透明度值,完成动画,代码如下:
AnimatedBuilder(
animation: opacityAnim,
builder: (ctx, child) => Opacity(
opacity: opacityAnim.value,
child: child,
),
child: Image.asset(
'assets/images/icon_head.png',
width: 100,
height: 100,
),
),
上面的方式可以达到一样的效果,那这和 FadeTransition
想必有什么劣势呢?首先,很明显使用 AnimatedBuilder
组件比较麻烦;其次使用 AnimatedBuilder
组件,每次动画器数值变化都会执行 builder
回调来创建组件,也就是说 Opacity
组件会被创建很多次。
而从 FadeTransition
源码中可以看出,对动画器的监听是在其对应的 RenderAnimatedOpacity
中进行的,也就是说,通过 FadeTransition
组件进行 透明度渐变动画
的整个动画过程,是没有伴随任何组件重建的。这就是其最大的优势。
FadeTransition 组件
的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~