前言:
这是我参与8月更文挑战的第 15 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战
,我准备在本月挑选 31
个以前没有介绍过的组件,进行全面分析和属性介绍。这些文章将来会作为 Flutter 组件集录
的重要素材。希望可以坚持下去,你的支持将是我最大的动力~
一、认识 AnimatedContainer 组件
在 Container 组件 一文中,我们知道它存在的价值是:整合如下 8 个单子组件,这样通过一个 Container
完成多种功能。可以避免在使用是层层嵌套,简化代码结构。而 AnimatedContainer
就相当于一个加强版的 Container
,可以让其中的各个属性在变化时具有动画效果
。
1.AnimatedContainer 基本信息
AnimatedContainer
是一个隐式动画
组件,和之前介绍过的 AnimatedOpacity 是同类,这种动画组件,只需要更改属性
+ 重新构建
就可以实现动画。这类的动画组件,都有一些共同的属性,如 duration
表示动画时长、curve
表示动画曲线、onEnd
表示动画结束的回调。
下面可以对比一下 AnimatedContainer
和 Container
的属性,可以看出基本是一模一样的。也就是说了解 Container
属性的用法之后,其实 AnimatedContainer
自然也就会了。两者的区别只在于:Container
在属性变化重构后,是直接变换,而 AnimatedContainer
是动画渐变。
2. AnimatedContainer 组件的使用
我们先通过一个简单的例子看一下 AnimatedContainer
的使用方式。如下,当点击按钮时,通过 _changeSize
方法改变宽高数值,并重建组件。可以看出 AnimatedContainer
尺寸变化会有动画效果。想一下,如果这里使用 Container
组件,那么将会直接改变到对应数值,就比较生硬。
class AnimatedContainerDemo extends StatefulWidget {
@override
_AnimatedContainerDemoState createState() => _AnimatedContainerDemoState();
}
class _AnimatedContainerDemoState extends State<AnimatedContainerDemo> {
double _width = 180;
double _height = 120;
@override
Widget build(BuildContext context) {
return Wrap(
direction: Axis.vertical,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
ElevatedButton(
child: const Text('更新宽高'),
onPressed: _changeSize,
),
const SizedBox(height: 10,),
buildAnimatedContainer()
],
);
}
Widget buildAnimatedContainer() => AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
height: _height,
color: Colors.black12,
width: _width,
onEnd: onEnd,
);
void onEnd() {
print('End');
}
void _changeSize() {
setState(() {
_width = _width == 100 ? 180 : 100;
_height = _height == 100 ? 120 : 100;
});
}
}
3.AnimatedContainer 组件的其他属性
AnimatedContainer
的其他某些属性也可以进行动画,比如下面的 alignment
和 color
。和宽高一样,只需要改变属性值
和重构组件
,就能进行动画。不需要处理动画器,这就是隐式动画的方便之处。
Alignment _alignment = Alignment.topLeft;
Color _color = Colors.orange;
Widget buildAnimatedContainer() => AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
height: 100,
color: _color.withOpacity(0.2),
width: 100,
alignment: _alignment,
onEnd: onEnd,
child: FlutterLogo(),
);
void _change() {
setState(() {
_alignment =
_alignment == Alignment.center ?
Alignment.topLeft : Alignment.center;
_color = _color == Colors.orange ?
Colors.purple : Colors.orange;
});
}
我们也可以对 decoration
属性进行动画,如下的圆角和阴影装饰,也是只需要改变属性值
和重构组件
即可。
总的来说 AnimatedContainer
的属性意义和 Container
一模一样,只是前者在属性变化重构时
会进行动画过渡到该值。这样会使变化显得不那么突兀,视觉上更好些。其他的属性参考 Container 组件 一文,大家可以自己试试改变这些属性的效果。
二、AnimatedContainer 的源码实现
AnimatedContainer
继承自 ImplicitlyAnimatedWidget
,这也就说明它和 AnimatedOpacity 是同族的,所以他们在源码实现上是类似的。
不同点在于AnimatedOpacity
是通过 FadeTransition
组件实现的动画渐变功能,该组件天生可以监听 Listenable
对象触发重绘。而 _AnimatedContainerState
继承自 AnimatedWidgetBaseState
。
AnimatedWidgetBaseState
中会监听动画控制器 controller
,通过 setState
对子组件进行 局部更新
。其原理和 AnimatedBuilder
是一致的。
从状态类中维护的 XXXTween
可以看出能够进行动画的属性有哪些。从组件的构建中可以看出,本身还是使用了 Container
实现的。由于之前监听了动画,并执行setState
,那么在动画的每一帧,都会更新 Container
的属性配置信息,进行局部更新
。
最后,动画的开启和 AnimatedOpacity 一文中介绍的一样,比较他们都是 ImplicitlyAnimatedWidget
。动画器的维护都封装在 ImplicitlyAnimatedWidgetState
中:
当 StatefulWidget
重新构建时,状态类是不会重新初始化的。而是触发 State#didUpdateWidget
来通知 Widget
配置的变更,在此可以处理一下组件更新的逻辑。可以看出,如下在 didUpdateWidget
中,会对配置进行对比,发生变化将会更新。最后 _controller
会执行 forward
进行动画。
那AnimatedContainer
的使用方式到这里就介绍完毕,那本文到这里就结束了,谢谢观看,明天见~