写点什么

flutter 系列之: 深入理解布局的基础 constraints

作者:程序那些事
  • 2022 年 6 月 17 日
  • 本文字数:2807 字

    阅读完需:约 9 分钟

简介

我们在 flutter 中使用 layout 的时候需要经常对组件进行一些大小的限制,这种限制就叫做 constraints,用来控制 layout 中的组件大小。


掌握了 constraints 才算对 layout 有了真正的了解,但是 flutter 中的 constraints 和我们熟悉的 HTML 中的 constraints 区别比较大,所以我们还是需要深入了解 flutter 中 contraints 的特性。

Tight 和 loose constraints

对于 constraints 来说,只有四个属性,分别是最小 width,最大 width,最小 height 和最大 height。这四个属性所能限制的就是宽度和高度的范围。


根据这两个属性的范围不同,constraints 可以分为 tight constraints 和 loose constraints。


那么 tight 和 loose 有什么区别呢?


对于 tight 来说,它的 maximum width = minimum width, 并且 maximum height = minimum height, 也就是说为 width 和 height 提供了一个特定的值。


具体而言,可以看下 BoxConstraints 的 tight 实现:


BoxConstraints.tight(Size size)   : minWidth = size.width,     maxWidth = size.width,     minHeight = size.height,     maxHeight = size.height;
复制代码


和 tight 相对应的就是 loose,在 loose 中我们设置了最大的 width 和 height,但是希望 widget 越小越好,这样对应 width 和 height 的最小值为 0,同样以 BoxConstraints 为例看下它的定义:


BoxConstraints.loose(Size size)   : minWidth = 0.0,     maxWidth = size.width,     minHeight = 0.0,     maxHeight = size.height;
复制代码

理解 constraints 的原则

前面我们讲到了 constraints 的分类,这里我们会讲一下 constraints 的基本原则。


通常来说,在 flutter 中,一个 widget 的 constraints 是从它的 parent 继承而来的。然后这个 widget 会将 constraints 告诉他的子 widget.


子 widget 会有自己定义的大小,那么子 widget 会根据自己定义的大小来设置自己的大小,并将结果反馈跟父 widget,父 widget 会最终根据所有子 widget 的大小来设置自己的大小。


所以总结而言就是,constraints 是向下传递的,而 size 是向上传递的。


可能大家还不太明白是什么意思,没关系,接下来我们用具体的例子来说明。


首先,我们使用 BoxConstraints.tightFor 来创建一个尽可能大的 width 和 height 的 Constraints,然后在这个 constraint 内部新建 widget 来观察他们的表现。


ConstrainedBox(     constraints: const BoxConstraints.tightFor(           width: double.infinity, height: double.infinity),            child: exampleWidget)
复制代码


通过替换上面的 exampleWidget,我们来观察不同的表现形式。


首先是最基础的 Container,对于 Container 本身来说,他可以设置 width 和 height,但是这两个属性并不是 constraint,所以还得从 parent widget 中继承。


那么对于下面的一个 widget 来说:


  Widget build(BuildContext context) {    return Container(color: blue);  }
复制代码


它会使用从 parent 继承的 constraints,也就是说尽可能的大,所以会展示下面的界面:



填满所有的区域。


如果给 Container 指定了 width 和 hight,同样的,Container 需要从 parent 继承 constraints,所以仍然是填满整个区域:


  Widget build(BuildContext context) {    return Container(width: 100, height: 100, color: blue);  }
复制代码


但是,如果我们在 Container 的外面再加上一个 constraints,比如 Center:


  Widget build(BuildContext context) {    return Center(      child: Container(width: 100, height: 100, color: blue),    );  }
复制代码


那么虽然 Center 会从 parent 继承 constraints,去填满整个区域,但是 Center 本身的 constraints 是告诉子 widget 可以按照他自己的意愿来调整大小,所以这个时候最终 Container 的大小就是 100x100:



除了 Center 之外,我们还可以使用 Align,效果和 Center 是一致的:


  Widget build(BuildContext context) {    return Align(      alignment: Alignment.bottomLeft,      child: Container(width: 100, height: 100, color: blue),    );  }
复制代码



下面是一个使用 Center 的很有趣的例子:


  Widget build(BuildContext context) {    return Center(      child: Container(        color: blue,        child: Container(color: green, width: 30, height: 30),      ),    );  }
复制代码


这里 Center 中有一个 Container,Container 中有一个 Container,但是这两个 Container 设置了不同的颜色。


因为外层的 Container 并没有设置大小,所以他的大小是由 child Container 来决定的,因为两个 Container 大小一样,所以外部的颜色会被内部的覆盖,我们可以得到下面的界面:



如果我们给外层的添加一个 padding 如下:


  Widget build(BuildContext context) {    return Center(      child: Container(        padding: const EdgeInsets.all(20.0),        color: blue,        child: Container(color: green, width: 30, height: 30),      ),    );  }
复制代码


那么外层现在就比内层的 widget 要大了,颜色也可以展示出来了:



我们再来看下面的例子:


  Widget build(BuildContext context) {    return ConstrainedBox(      constraints: const BoxConstraints(        minWidth: 70,        minHeight: 70,        maxWidth: 150,        maxHeight: 150,      ),      child: Container(color: blue, width: 10, height: 10),    );  }
复制代码


上面的例子在 Container 外面添加了一个 ConstrainedBox,指定了四个 constraints 属性,但是这个 ConstrainedBox 并不会应用到 child 上,所以最终得到的界面还是全部的蓝色。


为什么呢?这是因为不同的 widget 对 constraints 有不同的定义,对于 ConstrainedBox 来说,他是一个对其子项施加额外约束的小部件。记住,这里是额外的约束。因为对于它的 parent 来说,约束已经制定好了,所以 ConstrainedBox 会被忽略。


我们再看下下面的代码:


  Widget build(BuildContext context) {    return Center(      child: ConstrainedBox(        constraints: const BoxConstraints(          minWidth: 70,          minHeight: 70,          maxWidth: 150,          maxHeight: 150,        ),        child: Container(color: blue, width: 10, height: 10),      ),    );  }
复制代码


这里因为使用了 Center,Center 会让 child 来自行决定他们的大小,所以这里的 ConstrainedBox 是生效的,如下:



flutter 中除了 ConstrainedBox,还有一个 UnconstrainedBox,它的作用和 ConstrainedBox 是相反的,大家可以自行尝试。

总结

从上面的具体例子,我们可以看出,虽然我们有通用的 Constraint 规则,但是具体的表现还是要看不同的 widget 来定。


所以大家在使用 widget 的时候,一定要去读一下 widget 的代码,从而加深对 widget 的掌握。


本文的例子:https://github.com/ddean2009/learn-flutter.git


更多内容请参考 http://www.flydean.com/13-flutter-ui-constraints/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 刚刚阅读数: 2
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
flutter系列之:深入理解布局的基础constraints_flutter_程序那些事_InfoQ写作社区