注册

【Flutter 组件集录】SizedBox

一、认识 SizedBox 组件

源码中对 SizedBox 的介绍为:一个指定尺寸的盒子。那 SizedBox 为什么可以限定尺寸?背后区域限定的原理又是什么? 本文通过 SizedBox 来一窥布局约束奥秘的冰山一角。





1.SizedBox 基本信息

下面是 SizedBox 组件类的定义构造方法,可以看出它继承自 SingleChildRenderObjectWidget。可接受一个子组件,和区域的宽高。





2.SizedBox 的使用

如下,是一个 100*50SizedBox ,通过 ColoredBox 涂上蓝色,效果如下:



SizedBox(
width: 100,
height: 50,
child: ColoredBox(
color: Colors.blue.withAlpha(88)
),
),



3.区域分析

乍一看,不就是一个组件提供宽高来设置尺寸吗,似乎并没有什么好延伸的。但你有没有想过,为什么 SizedBox 有权力决定尺寸大小?它决定的区域一定有效吗?在分析之前,先了解一些前置知识:


任何组件的占位区域绘制内容最终都取决于 RenderObject 。而并非所有的组件都和 RenderObject 有关,只有 RenderObjectWidget 负责维护 RenderObject 。像 StatelessWidgetStatefulWidget 这种都是基于已有组件进行组合,往深层去看,他们都是基于某些 RenderObjectWidget 实现。


关于布局, RenderObject 有一个非常重要的属性: Constraints 类型的 constraints ,表示自身受到的区域约束限制。而 RenderBox 作为 RenderObject 的子类,拓展出了 size 的概念,绝大多数组件维护的渲染对象都是在 RenderBox 基础上进行拓展的。


下面来打开组件树,一起来看一下:



上面的 SizedBox 组件,它维护的 RenderObjectRenderConstrainedBox ,自身的约束为 [w(0,800) - h(0,600)] ,也就说明该渲染对象的大小必须在这此区间内。然后它会给子组件施加一个额外的约束 [w(100,100) - h(50,50)]


这样对于 ColoredBox 对应的渲染对象 _RenderColoredBox ,由于父级施加的额外约束,自身的约束也就变成 [w(100,100) - h(50,50)] 。也就说明该渲染对象的大小必须在这此区间内,即 _RenderColoredBox 的尺寸被限定为 (100,50)


_RenderColoredBoxsize 确定后,RenderConstrainedBox 会根据自身的约束和子节点的尺寸来确定自身的尺寸。这就是 SizedBox 的工作原理。




4、约束测试

为了更好地说明约束的作用,这里进行一下测试,在之前的案例的 SizedBox 外层通过 ConstrainedBox 组件添加添加一个 [w(20,20) - h(20,20)] 的强制约束。可以看出即使 SizedBox 设置了固定的宽高,但是在外层的约束之下,会优先满足父级约束。


[推论1] SizedBox 的最终尺寸会受到父级约束的影响,并非一定为指定值。


ConstrainedBox(
constraints: BoxConstraints(
minWidth: 20,
maxWidth: 20,
maxHeight: 20,
minHeight: 20,
),
child: SizedBox(
width: 100,
height: 50,
child: ColoredBox(color: Colors.blue.withAlpha(88)),
),
);



我们再来看一下此时的组件树:
可以看出 SizedBox 维护的 RenderConstrainedBox 本身的约束区域为 [w(20,20) - h(20,20)] ,为子节点施加的额外约束为 [w(100,100) - h(50,50)] 。在 ColoredBox 维护的 _RenderColoredBox 中,约束区域为 [w(20,20) - h(20,20)] ,这也就觉得了其尺寸为 (20,20)



这样可以看出,渲染对象对子节点施加的额外约束 ,并不会完全作用于子节点。还会根据自身的约束情况,来确定子组件的最终约束。




三、SizedBox 的源码分析


SizedBox 继承自 SingleChildRenderObjectWidget ,就说明它需要维护一个 RenderObject 来实现功能。





在前面我们通过组件树可以看出,它维护的渲染对象是 RenderConstrainedBox 。从源码中可以看出, RenderConstrainedBox 构造时需要传入一个约束对象 BoxConstraints 。这里通过 BoxConstraints.tightFor 构造使用 widthheight 创建一个紧约束。



通过源码可以看出,这个构造的约束为: [w(width,width) - h(height,height)],也就是固定宽高约束。





SizedBox 除了普通构造之外,还有三个命名构造。如果已经了解上面的用法,那这三个也非常简单,都逃离不了对宽高的初始化。比如 .expand 会创建一个无限的约束,这样由于 推论1 ,其约束的尺寸就可以在父级的约束下,尽可能的大 。 .shrink 就是一个 [w(0,0) - h(0,0)]的限制,同理,会在父级的约束下,尽可能的小。



至于 RenderConstrainedBox 渲染对象的实现,将在后面的 ConstrainedBox 一文中进行介绍,毕竟 RenderConstrainedBox 的本命是 ConstrainedBox 。通过本文,你应该对 SizedBox 有了更深的认识,对布局约束、尺寸确定也认识了九牛一毛 。那本文到这里就结束了,谢谢观看,明天见~

0 个评论

要回复文章请先登录注册