前言:
这是我参与8月更文挑战的第 9 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战
,我准备在本月挑选 31
个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录
的重要素材。希望可以坚持下去,你的支持将是我最大的动力~
一、认识 AnimatedOpacity 组件
上两篇介绍了 Opacity 组件 和 FadeTransition 组件,他们都和操作组件的透明度有关。除了这两位,还有一个组件也和透明度有关,它就是: AnimatedOpacity
。和 FadeTransition 组件的功能是一样的,它也可以进行 透明度渐变动画
。那他和 FadeTransition
有什么异同点,为什么框架中会给出两个功能一致的组件?带着这个问题,我们来开始认识 AnimatedOpacity
组件。
1.AnimatedOpacity 基本信息
我们通过继承树可以看出,该组件继承自 ImplicitlyAnimatedWidget
,是一个 StatefulWidget
。 ImplicitlyAnimatedWidget
称之为 隐式动画
,其最大的特点是: 使用者无需自己提供 动画器
,也可以进行动画变换。
通过 AnimatedOpacity
的构造入参,可以发现,它确实不需要传入动画器,但可以指定动画相关的 时长
和 动画曲线
。从这里,很容易猜出 ImplicitlyAnimatedWidget
相关类会维护 动画控制器
,封装动画的操作。这样的目的很清楚:避免用户直接和 动画器
打交道,方便使用。从这里可以衍生出一个问题 : 既然用户无法直接操纵动画器,那么动画是如何被开启的?
带着问题,继续往下看。
2.AnimatedOpacity 的使用
我们先来看一个 AnimatedOpacity
使用的小 demo
。如下,通过 Switch
来切换 AnimatedOpacity
中 opacity
的值。可见,当 opacity
配置属性变化时,就会执行动画。
下面代码中,通过 Wrap
组件,竖直包裹 Switch
和 Container
,其中容器里放着 AnimatedOpacity
,让一个图标进行动画变化。在 Switch
点击时,重新构建 AnimatedOpacity
并更新 opacity
的配置值。然后就神奇地执行动画了,可以看出,动画的执行和组件重构是有关系的。
class AnimatedOpacityDemo extends StatefulWidget {
@override
_AnimatedOpacityDemoState createState() => _AnimatedOpacityDemoState();
}
class _AnimatedOpacityDemoState extends State<AnimatedOpacityDemo> {
final double beginOpacity = 1.0;
final double endOpacity = 0;
late double _opacity;
@override
void initState() {
super.initState();
_opacity = beginOpacity;
}
bool get selected => _opacity == 0;
@override
Widget build(BuildContext context) {
return Wrap(
direction: Axis.vertical,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
Switch(
value: selected,
onChanged: onChanged,
),
Container(
color: Colors.grey.withAlpha(22),
width: 100,
height: 100,
child: buildAnimatedOpacity(),
),
],
);
}
Widget buildAnimatedOpacity() =>
AnimatedOpacity(
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
opacity: _opacity,
child: _buildChild(),
);
void onChanged(bool value) {
setState(() {
_opacity = value ? endOpacity : beginOpacity;
});
}
Widget _buildChild() =>
const Icon( Icons.add_to_drive, color: Colors.green, size: 60 );
}
3.AnimatedOpacity 的价值
AnimatedOpacity
组件最大的亮点在于只要其 opacity
属性发生变化,并重新构建,就可以进行动画。下面的案例更能体现它的价值:通过 Slider
的滑动,控制 AnimatedOpacity
的 opacity
属性变化,及重新构建。这样每当滑动到新的值,都会 动画渐变
到该透明度,如果使用 FadeTransition
组件,自己操作纵动画器来实现,就会比较复杂。 AnimatedOpacity
组件这类的隐式动画大大降低
了用户使用动画的门槛
。
// Slider 组件构建
Container(
height: 50,
child: Slider(
label: "$_opacity",
value: _opacity,
divisions: 5,
onChanged: onChanged,
),
),
void onChanged(double value) {
setState(() {
_opacity = value;
});
}
另外,AnimatedOpacity
可以通过 onEnd
回调监听动画执行完毕的时机。
三、 AnimatedOpacity 的源码实现
1. AnimatedOpacity 源码分析
前面说过 AnimatedOpacity
继承自 ImplicitlyAnimatedWidget
。
而 ImplicitlyAnimatedWidget
做为 StatefulWidget
需要实现 createState
创建 State
对象,但由于其是抽象类,可以选择不实现,交由子类完成。
ImplicitlyAnimatedWidget
中没有实现 createState
,而把返回的状态类型将限制为 ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget>
。
AnimatedOpacity
作为 ImplicitlyAnimatedWidget
子类,需要实现 createState
抽象方法。如下,状态类为 _AnimatedOpacityState
。
这样组件层面
的源码就理清了,ImplicitlyAnimatedWidget
相当于一个中间层,可以通过 ImplicitlyAnimatedWidgetState
额外做一些事情。其子类组件的创建的状态类,也需要继承自 ImplicitlyAnimatedWidgetState
。下面就来看看,状态类做了什么。
2. 状态类的处理
实现来看作为实现类的 _AnimatedOpacityState
。非常简单,就是维护 _opacityAnimation
,依赖于 FadeTransition
组件进行动画。是不是想直呼 好家伙
。
动画控制器的源泉在于抽象的状态类 ImplicitlyAnimatedWidgetState
,这里将进行 动画控制器
的监听、开启等维护工作。
在 initState
中会对动画器进行监听,如果动画完成,会执行 onEnd
回调。
3. 动画的开启
看到这里,你应该能猜出来动画触发的时机。当 StatefulWidget
重新构建时,状态类是不会重新初始化的。而是触发 State#didUpdateWidget
来通知 Widget
配置的变更,在此可以处理一下组件更新的逻辑。可以看出,在 ImplicitlyAnimatedWidgetState#didUpdateWidget
中,会对配置进行对比,发生变化将会更新。最后 _controller
会执行 forward
进行动画。
AnimatedOpacity
组件,本质上就是对 动画控制器
和 FadeTransition
组件的一层封装。简化用户对动画使用的门槛,降低动画使用的错误率。其他的隐式动画组件也是类似,AnimatedOpacity
的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~