布局组件分类
1.ConstrainedBox
ConstrainedBox
用于对子组件增加额外的束缚。假如想让子组件的最小高度是80像素,你能够运用const BoxConstraints(minHeight: 80.0)
作为子组件的束缚
ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity, //宽度尽可能大
minHeight: 50.0 //最小高度为50像素
),
child: Container(
height: 5.0,
child: redBox ,
),
)
能够看到,咱们尽管将Container的高度设置为5像素,可是终究却是50像素,这正是ConstrainedBox的最小高度束缚收效了。假如将Container的高度设置为80像素,那么终究赤色区域的高度也会是80像素,由于在此示例中,ConstrainedBox只束缚了最小高度,并未束缚最大高度
2. SizedBox
SizedBox
用于给子元素指定固定的宽高 如:
SizedBox(
width: 80.0,
height: 80.0,
child: redBox
)
实际上SizedBox
只是ConstrainedBox
的一个定制,上面代码等价于:
ConstrainedBox(
constraints: BoxConstraints.tightFor(width: 80.0,height: 80.0),
child: redBox,
)
而BoxConstraints.tightFor(width: 80.0,height: 80.0)
等价于:
BoxConstraints(minHeight: 80.0,maxHeight: 80.0,minWidth: 80.0,maxWidth: 80.0)
2. 多重束缚
假如某一个组件有多个父级ConstrainedBox
束缚,那么终究会是哪个收效?
ConstrainedBox(
constraints: BoxConstraints(minWidth: 60.0, minHeight: 60.0), //父
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),//子
child: redBox,
),
)
咱们有父子两个ConstrainedBox
,他们的束缚条件不同 作用如图:
终究显现作用是宽90,高60,也便是说是子ConstrainedBox
的minWidth
收效,而minHeight
是父ConstrainedBox
收效。
再看下面比方:
ConstrainedBox(
constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: 60.0, minHeight: 60.0),
child: redBox,
)
)
终究的显现作用依然是90,高60,作用相同,但含义不同,由于此刻minWidth
收效的是父ConstrainedBox
,而minHeight
是子ConstrainedBox
收效。
经过上面示例,咱们发现有多重束缚时,对于minWidth
和minHeight
来说,是取父子中相应数值较大的。实际上,只有这样才能确保父束缚与子束缚不冲突。
3.UnconstrainedBox
尽管任何时分子组件都必须恪守其父组件的束缚,但前提条件是它们必须是父子关系,假如有一个组件 A,它的子组件是B,B 的子组件是 C,则 C 必须恪守 B 的束缚,同时 B 必须恪守 A 的束缚,可是 A 的束缚不会直接束缚到 C,除非B将A对它自己的束缚透传给了C。 运用这个原理,就能够实现一个这样的 B 组件:
- B 组件中在布局 C 时不束缚C(能够为无限大)。
- C 依据本身真实的空间占用来确认本身的巨细。
- B 在恪守 A 的束缚前提下结合子组件的巨细确认本身巨细。
而这个 B组件便是UnconstrainedBox
组件,也便是说UnconstrainedBox
的子组件将不再受到束缚,巨细完全取决于自己。一般情况下,咱们会很少直接运用此组件,但在”去除”多重束缚的时分也许会有帮助,咱们看下下面的代码:
ConstrainedBox(
constraints: BoxConstraints(minWidth: 60.0, minHeight: 100.0), //父
child: UnconstrainedBox( //“去除”父级束缚
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),//子
child: redBox,
),
)
)
上面代码中,假如没有中心的UnconstrainedBox
,那么依据上面所述的多重束缚规矩,那么终究将显现一个90100的赤色框。可是由于UnconstrainedBox
“去除”了父ConstrainedBox
的束缚,则终究会依照子ConstrainedBox
的束缚来绘制redBox
,即9020,如图
可是,读者请留意,UnconstrainedBox
对父组件束缚的“去除”并非是真正的去除:上面比方中尽管赤色区域巨细是9020,但上方依然有80的空白空间。也便是说父束缚的minHeight
(100.0)依然是收效的,只不过它不影响终究子元素redBox
的巨细,但依然还是占有相应的空间,能够认为此刻的父ConstrainedBox
是作用于子UnconstrainedBox
上,而redBox
只受子ConstrainedBox
束缚,这一点请读者必须留意。
那么有什么办法能够彻底去除父ConstrainedBox
的束缚吗?答案是否定的!请紧记,任何时分子组件都必须恪守其父组件的束缚,所以在此提示读者,在定义一个通用的组件时,假如要对子组件指定束缚,那么必定要留意,由于一旦指定束缚条件,子组件本身就不能违反束缚。
在实际开发中,当咱们发现已经运用SizedBox
或ConstrainedBox
给子元素指定了固定宽高,可是依然没有作用时,简直能够判定:已经有父组件指定了束缚!举个比方,如 Material 组件库中的AppBar
(导航栏)的右侧菜单中,咱们运用SizedBox
指定了 loading 按钮的巨细,代码如下:
AppBar(
title: Text(title),
actions: <Widget>[
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation(Colors.white70),
),
)
],
)
作用如图
咱们会发现右侧loading按钮巨细并没有发生变化!这正是由于AppBar
中已经指定了actions
按钮的束缚条件,所以咱们要自定义loading按钮巨细,就必须经过UnconstrainedBox
来 “去除” 父元素的束缚,代码如下:
AppBar(
title: Text(title),
actions: <Widget>[
UnconstrainedBox(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation(Colors.white70),
),
),
)
],
)
运转后作用如图
收效了!实际大将 UnconstrainedBox 换成 Center 或者 Align 也是能够的,至于为什么,咱们会在本书后边布局原理相关的章节中解释。
另外,需求留意,UnconstrainedBox 尽管在其子组件布局时能够撤销束缚(子组件能够为无限大),可是 UnconstrainedBox 本身是受其父组件束缚的,所以当 UnconstrainedBox 跟着其子组件变大后,假如UnconstrainedBox 的巨细超越它父组件束缚时,也会导致溢出报错,比方:
Column(
children: <Widget>[
UnconstrainedBox(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(children: [Text('xx' * 30)]),
),
),
]
运转作用如图