【Flutter 组件集录】SizedBox
一、认识 SizedBox 组件
源码中对 SizedBox
的介绍为:一个指定尺寸的盒子。那 SizedBox
为什么可以限定尺寸?背后区域限定的原理又是什么? 本文通过 SizedBox
来一窥布局约束奥秘的冰山一角。
1.SizedBox 基本信息
下面是 SizedBox
组件类的定义
和 构造方法
,可以看出它继承自 SingleChildRenderObjectWidget
。可接受一个子组件,和区域的宽高。
2.SizedBox 的使用
如下,是一个 100*50
的 SizedBox
,通过 ColoredBox
涂上蓝色,效果如下:
SizedBox(
width: 100,
height: 50,
child: ColoredBox(
color: Colors.blue.withAlpha(88)
),
),
3.区域分析
乍一看,不就是一个组件提供宽高来设置尺寸吗,似乎并没有什么好延伸的。但你有没有想过,为什么 SizedBox
有权力决定尺寸大小?它决定的区域一定有效吗?在分析之前,先了解一些前置知识:
任何组件的占位区域
、绘制内容
最终都取决于 RenderObject
。而并非所有的组件都和 RenderObject
有关,只有 RenderObjectWidget
负责维护 RenderObject
。像 StatelessWidget
和 StatefulWidget
这种都是基于已有组件进行组合,往深层去看,他们都是基于某些 RenderObjectWidget
实现。
关于布局, RenderObject
有一个非常重要的属性: Constraints
类型的 constraints
,表示自身受到的区域约束限制。而 RenderBox
作为 RenderObject
的子类,拓展出了 size
的概念,绝大多数组件维护的渲染对象
都是在 RenderBox
基础上进行拓展的。
下面来打开组件树,一起来看一下:
上面的 SizedBox
组件,它维护的 RenderObject
是 RenderConstrainedBox
,自身的约束为 [w(0,800) - h(0,600)]
,也就说明该渲染对象的大小必须在这此区间内。然后它会给子组件施加一个额外的约束 [w(100,100) - h(50,50)]
。
这样对于 ColoredBox
对应的渲染对象 _RenderColoredBox
,由于父级施加的额外约束,自身的约束也就变成 [w(100,100) - h(50,50)]
。也就说明该渲染对象的大小必须在这此区间内,即 _RenderColoredBox
的尺寸被限定为 (100,50)
。
_RenderColoredBox
的 size
确定后,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
构造使用 width
和 height
创建一个紧约束。
通过源码可以看出,这个构造的约束为: [w(width,width) - h(height,height)]
,也就是固定宽高约束。
SizedBox
除了普通构造之外,还有三个命名构造。如果已经了解上面的用法,那这三个也非常简单,都逃离不了对宽高的初始化。比如 .expand
会创建一个无限的约束,这样由于 推论1
,其约束的尺寸就可以在父级的约束
下,尽可能的大 。 .shrink
就是一个 [w(0,0) - h(0,0)]
的限制,同理,会在父级的约束
下,尽可能的小。
至于 RenderConstrainedBox
渲染对象的实现,将在后面的 ConstrainedBox
一文中进行介绍,毕竟 RenderConstrainedBox
的本命是 ConstrainedBox
。通过本文,你应该对 SizedBox
有了更深的认识,对布局约束、尺寸确定也认识了九牛一毛 。那本文到这里就结束了,谢谢观看,明天见~