刚看到这个 widget 的时候,有点奇怪,已经有了 AnimatedWidget 和 ImplicitlyAnimatedWidget,感觉已经无所不能了啊,怎么还有个 AnimatedSize。存在肯定有他的价值,让我们来一探究竟吧。
可以这样给 AnimatedSize 下定义:一个有动画能力的布局 widget。AnimatedSize 和 AnimatedWidget、 ImplicitlyAnimatedWidget 相比,是完全不同的 widget。AnimatedSize 的动画是在 renderObject 实现的,效率更高。动画是由 child 驱动的,而不是由外界通过参数指定。
动画能力是附加的,本质上 AnimateSize 是一个布局 widget,所以第一步,按布局三板斧来研究。我们通过查看源码来研究下 child 的 constrains,AnimatedSize 的 size 和摆放 child
child 的 constrains
void performLayout() {
_lastValue = _controller.value;
_hasVisualOverflow = false;
final BoxConstraints constraints = this.constraints;
if (child == null || constraints.isTight) {
_controller.stop();
size = _sizeTween.begin = _sizeTween.end = constraints.smallest;
_state = RenderAnimatedSizeState.start;
child?.layout(constraints);
return;
}
child!.layout(constraints, parentUsesSize: true);
... 后面省略
在把 constrains 赋值给child 之前, AnimatedSize 并没有对 constrains 做修改,直接透传给了chid
AnimatedSize 的 size
- constrains 是 tight,size = constraints.smallest。
- constrains 是 loose, size 在 constrains 范围内取 childSize 的大小。
如果 childSize 发生变化引发了动画, size 在 constrains 的范围取 _animatedSize。
_animatedSize 也就是动画过程中某一时间点上的值。
Size? get _animatedSize {
return _sizeTween.evaluate(_animation);
}
摆放 child
只有 size 和 childSize 不一样的时候才能摆放 child。
只有一个情况下 size 比 childSize 大。当 child size 从大变小的时候,child 是直接没有过渡的直接变小,AnimatedSize 要执行动画,所以是慢慢变小,这个时候就会出现 size 比 childSize 大的情况。
如何摆放 child 是 alignment 参数控制的。
使用 AnimatedSize
百说不如一练。我们看一个例子。就是一个简单的 box,点击它会变大变小。
double _size = 250.0;
bool _large = false;
void _updateSize() {
setState(() {
_size = _large ? 250.0 : 100.0;
_large = !_large;
});
}
Center(
child: GestureDetector(
onTap: () => _updateSize(),
child: Container(
color: Colors.amberAccent,
child: AnimatedSize(
alignment: Alignment.center,
curve: Curves.easeIn,
duration: const Duration(seconds: 1),
child: Container(
width: _size,
height: _size,
color: Colors.green,
)),
)))
黄色代表 AnimatedSize size,绿色代表 childSize。你可能会有疑问,为什么变大的时候,child 和 parent 一起变大,而变小的时候,child 直接变小,而 parent 慢慢变小呢。其实这只是假象,真实情况都是 child 直接变大变小,parent 慢慢变大变小。变大的时候因为 AnimatedSize clip child ,把 child 裁剪了,所以感觉上好像和 AnimatedSize 一样大。
做个实验 加上 clipBehavior: Clip.none 看看效果,你会发现,变在的时候也是突然变大了。
AnimatedSize(
// 加上这句
clipBehavior: Clip.none,
...
再试着修改下 alignemnt alignment: Alignment.center 改为alignment: Alignment.bottomRight,,效果如下
总之, AnimatedWidget 和 ImplicitlyAnimatedWidget 的动画是由外面传参进行控制,而 AnimatedSize 是由内部分的 child 的 size 的变化引发动画过程,AnimatedSize 的动画的效率更高。