flutter 约束(constrains )实例研究

大家好,我是 17。

如果你是 web 前端开发,你一定会这样的体会, weight,height 都是作用于 element 本身

<div style='width:100px;height:100px; ></div>

在页面中,这个 div 的高宽一定是 100 高 100 宽的。带着这样的认识,当你学习 flutter的时候,很容易会觉得
container 的 width ,height,也是这样的作用。但事实上,container 的 width ,height 只是约束,container 实际的尺寸是由约束,孩子的尺寸,和本身的规则一起决定的。

flutter 中的布局遵循这样的原则 constrains go down ,sizes go up. Parent sets position. 直译过来就是 constrains 向下传递,sizes 向上传递。parent 决定尺寸。

Constrains

Constrains 是抽象类,不能直接用,我们实际用的是 BoxConstrains。看看 BoxConstrains 的构造函数

  const BoxConstraints({
    this.minWidth = 0.0,
    this.maxWidth = double.infinity,
    this.minHeight = 0.0,
    this.maxHeight = double.infinity,
  }) 

一共有四个值。默认值的意思是尺寸可以随意,没有限制。特别的,最大最小值相同的 contains 称为 tight constrains,最小值为0 的 contains 称为 loose contains。一般来说,只要最大最小不相同的都可以看成是 loose constrains。

下面我会举例子,不用 container ,因为它是一个复合 widget,比较复杂。因为是研究 contrains,所以只用最简单的 widget。第一个例子会给出完整代码,后面的例子只给出关键代码。

我是用 chrome,renderView 调整为 500 x 296,具体多少不重要,你只要知道看到这个数值就是满屏就行了。

例一

image.png

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return const DecoratedBox(decoration: BoxDecoration(color: Colors.green));
  }
}

把上面的代码 copy 到 main.dart中,执行,会发现全屏都是绿色。其间发生了如下的沟通过程。

  1. app 告诉 DecoratedBox, 你的尺寸必须是 500 x 296
  2. DecoratedBox 显示为 500 x 296

app 是如何告诉 DecoratedBox 的呢,是传 constrains 给 DecoratedBox

constraints: BoxConstraints(w=500.0, h=296.0)

例二

image.png

const Center(child: DecoratedBox(decoration: BoxDecoration(color: Colors.green)));

当用 Center 包装后,什么都不会显示。这涉及到 DecoratedBox 自身的规则,它会尽量小。

  1. app 告诉 Center, 你的尺寸必须是 500 x 296
  2. Center 告诉 DecoratedBox 你可以显示为任意尺寸,只要别超过 500 x 296
  3. DecoratedBox 最小可以显示为 0 ,所以我们就看不见了。

Center 传给 DecoratedBox 的约束

constraints: BoxConstraints(0.0<=w<=500.0, 0.0<=h<=296.0)

Center 继承 自 Align。 Align 的一个功能就是把 tight 约束 转为 loose 约束

例三

image.png

Center(
        child: ConstrainedBox(
            constraints: const BoxConstraints(minWidth: 100, minHeight: 100),
            child: const DecoratedBox(
                decoration: BoxDecoration(color: Colors.green))));

DecoratedBox 获得了最小尺寸约束,所以它只好显示为 100 x 100

每次都写全四个属性有点麻烦,所以 ConstrainedBox 给出了快捷构造函数,拿 tight举例,其它就不再赘述了。

BoxConstraints.tight(Size size)

Size只有两个参数,width,height

const Size(double width, double height)

用 BoxConstraints.tight可以构造出 最大最小相等的约束。

BoxConstraints.tight(Size(width:100,height:100)

等价于

BoxConstraints(minWidth: 100, minHeight: 100,maxHeight: 100,maxWidth: 100)

例四

image.png

const Center(
        child: SizedBox(
            width: 100,
            height: 100,
            child:  DecoratedBox(
                decoration: BoxDecoration(color: Colors.green))));

用 SizedBox 可以达到同样的效果,而且代码更简洁些。和 ConstrainedBox 相比,SizedBox 只能构造 tight 约束。

例五

image.png

const Center(
        child: SizedBox(
            width: 100,
            height: 100,
            child:SizedBox(
              width: 300,
              height:300,
            child:  DecoratedBox(
                decoration: BoxDecoration(color: Colors.green))))
            );

可能你会认为 box 会显示为 300 x 300,但实际上是 100 x 100,这是因为 SizedBox,ConstrainedBox 把综合父级和自身的 contains ,处理后传给子级。

因为父级传过来的是 tight 约束 SizedBox,ConstrainedBox 会忽略自身的约束。所以显示为 100 x100

例六

image.png

Center(
        child: ConstrainedBox(
            constraints:const BoxConstraints(maxHeight: 100),
            child:const SizedBox(
              width: 300,
              height:300,
            child:  DecoratedBox(
                decoration: BoxDecoration(color: Colors.green))))
            );

如果父级传过来的是 loose 约束,可以在父级允许的范围内修改.

  1. Center 传给 BoxConstraints
constraints: BoxConstraints(0.0<=w<=500.0, 0.0<=h<=296.0)
  1. BoxConstraints 传给 SizedBox
constraints: BoxConstraints(0.0<=w<=500.0, 0.0<=h<=100.0)\
  1. SizedBox 传给 BoxDecoration
BoxConstraints(w=300.0, h=100.0)

综合 例五 例六,我们可以得出结论

BoxConstraints,sizedBox 只能在父级允许的范围内做修改

例七

image.png

 UnconstrainedBox(
        child: DecoratedBox(decoration: BoxDecoration(color: Colors.green)));
  }
  1. app 传给 UnconstrainedBox
constraints: BoxConstraints(w=500.0, h=296.0)
  1. UnconstrainedBox 传给 DecoratedBox
constraints: BoxConstraints(unconstrained)

UnconstrainedBox的作用是去掉 contains。BoxDecoration 在没有任何约束的情况下,会显示为最小,也就是 0 x 0 ,所以我们看不见它了。

例八

image.png

Directionality(
        textDirection: TextDirection.ltr, child: Row(children: const [
          LimitedBox(maxWidth: 100,maxHeight: 100,
          child: SizedBox(width: 300,height: 300,
          child: DecoratedBox(decoration: BoxDecoration(color: Colors.green)),
          ),
         
          )
        ]));

Directionality 是 row 必须的上级,不然报错。Directionality 不处理 constraints,所以 app直接把 constraints传给了 Row

  1. app 传给 Row
constraints: BoxConstraints(w=500.0, h=296.0)
  1. Row 修改宽度的 contain 为不限并传给 LimitedBox
constraints: BoxConstraints(0.0<=w<=Infinity, 0.0<=h<=296.0)

修改宽度为 Infinity 是 Row 本身的算法。

  1. LimitedBox 修改 maxWidth 并传给 DecoratedBox
constraints: BoxConstraints(0.0<=w<=100.0, 0.0<=h<=296.0)

代码中 LimitedBox 修改了宽高,为什么只有 宽生效呢?

LimitedBox 只能修改 值 为 Infinity 的约束。

  1. SizedBox 加上自己的约束传给 DecoratedBox
constraints: BoxConstraints(w=100.0, h=296.0)

SizedBox 想达到高宽 都为 300 但还得满足在父级允许的范围内。所以 传给 DecoratedBox 的只能是 100 x 296

最终 DecoratedBox 显示为 100 x 296

和 Row 类似,Column会修改高度的 constrain 为 Infinity。

在 Row,Column 中 为了避免错误,一定要注意给children 增加约束。


在前面的例子中, 为了做纯的 constrains 研究,没有用 Container,因为 Container 有自己的特性,如果不知 constrains 的原理,会被它的特性误导,误以为是 constrains 起作用。下面举几个 Container 的例子,说说 Container的特性。

例九

image.png

Center(
        child: Container(
      color: Colors.green,
 ));

如果直接写Container( color: Colors.green) 会全屏绿好理解,因为是 app 要求 Container必须要显示为全屏,但是现在已经加了Center了啊。为什么还是全屏? 这个就是Container的特性之一,当没有孩子的时候,会尝试尽可能能的大。

image.png

例十

 Center(
    child: Container(
          width: 100,
      color: Colors.green,
    ));

image.png

例九中有一个词埋下了伏笔。“尝试”尽可能的大。“尝试”结果就是没有孩子,没有约束,尽可能的大,有约束就按约束来。

本例中,高度没有约束,所以占满屏幕,宽度有约束,显示为 100

例十一

Center(
        child: Container(
            color: Colors.red[300],
            child: Container(
              width: 100,
              height: 100,
              color: Colors.green,)));

image.png

明明外面还有一个红色的 Container,但怎么看不见呢。这时展示了 Container的另一个特性,当它有孩子的时候,尝试尽可能的小。

本例中,因为 Center 让 红色 Container 可以任意大小,只要不超过屏幕,但它有孩子 ,所以它决定要变得和孩子一样大。幸运的是孩子也没有超过屏幕,于是它就和孩子一样大了。但因为孩子的绿色覆盖了它的红色,所以我们看不到它了。

例十一

image.png

 Center(
        child: Container(
            color: Colors.red[300],
            padding: const EdgeInsets.all(20),
            child: Container(
              width: 100,
              height: 100,
              color: Colors.green,
  )));

当有pading的时候,就可以看到 红色的。特别的,这时的红色Container展示为 140 x 140

在没有约束的情况下 padding 越大,Container 越大,但如果是有约束呢?

例十二

image.png

 Center(
        child: Container(
            color: Colors.red[300],
            padding: const EdgeInsets.all(20),
            child: Container(
              padding: const EdgeInsets.all(60),
              width: 100,
              height: 100,
              color: Colors.green,
              child: Container(
                width: 50,
                height: 50,
                color: Colors.blue[400],
              ),
            )));

最里面加了一个 蓝色 Container,但是完全看不到,因为 Container的高宽是包含padding的,绿色Container的高宽为 100,padding 却点了 120,占了所有的空间,所以没有蓝色 Container的显示空间了。padding超出不会报错,超出按最大值算。

作为最后一例,详细解说一下

  1. app 告诉 Cetner ,你必须 为屏幕大小
  2. Cetner 告诉 红色 Container 你可以任意大小,但别超过屏幕
  3. 红色 Container 发自己有 padding ,所以它告诉 绿色 Container ,你可以任意大小,但别超过 (500 - 40) x (296 - 40),因为屏幕的高宽为 500 x 296 ,各减去 padding 40,也就是 460 x 256
  4. 绿色 Container 同减去 Padding 后告诉 蓝色 Container ,只能显示为 0 x 0
  5. 蓝色 Container 报告说,好的,我显示 为 0 x 0
  6. 绿色 Container,报告给 红色 Container 说 ,我显示为 100 x 100
  7. 红色 Container 报告给 Center 说, 我显示为 460 x 256
  8. Center 于是 把 红色 Container 放在中间,并上报给 app,我显示为全屏。

如果你完全理解了上面的全部,你就有了布局的坚实的基础了。虽然还有很多布局的 Widget 没有介绍,但原理已经解释了,其它的都可以举一反三。最后还特意介绍了 Container ,以便区分哪些是 约束的效果,哪些是 Container 自己的行为,这样才能更好的理解约束。

如果你觉得有所收获,给我点个贊吧~

参考

  1. 理解约束
  2. Container class
  3. Align Class
  4. ConstrainedBox class
  5. SizedBox-class
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IAM17前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值