约束

ConstrainedBox

ConstrainedBox 用于对子组件添加额外的约束。例如,如果你想让子组件的最小高度是 80 像素,你可以使用 const BoxConstraints(minHeight: 80.0)作为子组件的约束。

BoxConstraints

BoxConstraints 用于设置限制条件,它的定义如下:

const BoxConstraints({
  this.minWidth = 0.0, // 最小宽度
  this.minHeight = 0.0, // 最小高度
  this.maxWidth = double.infinity, // 最大宽度
  this.maxHeight = double.infinity // 最大高度
})

示例:

ConstrainedBox(
  constraints: BoxConstraints(
    minWidth: double.infinity, // 宽度尽可能大
    minHeight: 200.0 // 最小高度为200像素
  ),
  child: Container(
      height: 50,
      child: Flex(
        direction: Axis.horizontal,
        children: <Widget>[
          Expanded(
            flex: 2,
            child: Container(
              color: Colors.red,
            ),
          ),
          Expanded(
            flex: 1,
            child: Container(
              color: Colors.green,
            ),
          )
        ],
      )
  ),
);

注意到, 上面使用到了 ConstrainedBox, 规定最小高度为 200, 虽然子元素指定高度为 50, 但由于约束条件的限制还是 200; 但如果将子元素的高度调到 200 以上, 则以子元素的高度为准。

多重限制

有多重限制时,对于 minWidth 和 minHeight 来说,是取父子中相应数值较大的。

比如:

ConstrainedBox(
  constraints: BoxConstraints(minWidth: 90.0, minHeight: 20.0),
  child: ConstrainedBox(
    constraints: BoxConstraints(minWidth: 60.0, minHeight: 60.0),
    child: redBox,
  )
)

最终取: minWidth: 90.0, minHeight: 60.0

SizedBox

SizedBox 用于给子元素指定固定的宽高,如:

SizedBox(
  width: 80.0,
  height: 80.0,
  child: ...
)

BoxConstraints.tightFor

实际上 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)

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,那么根据上面所述的多重限制规则,那么最终将显示一个 90×100 的红色框。但是由于 UnconstrainedBox “去除”了父 ConstrainedBox 的限制,则最终会按照子 ConstrainedBox 的限制来绘制 redBox,即 90×20:

但是,UnconstrainedBox 对父组件限制的“去除”并非是真正的去除:上面例子中虽然红色区域大小是 90×20,但上方仍然有 80 的空白空间。也就是说父限制的 minHeight(100.0)仍然是生效的,只不过它不影响最终子元素 redBox 的大小,但仍然还是占有相应的空间,可以认为此时的父 ConstrainedBox 是作用于子 UnconstrainedBox 上,而 redBox 只受子 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),
              ),
          ),
      )
  ],
)

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress