Flutter系列教程之布局约束

58 阅读4分钟

Flutter中的布局是向下约束的,即父组件的宽、高、位置并不决定父组件的大小,而是决定子组件能占用的大小和位置,而子组件设置的宽高又告诉父组件,我申请占用的大小。组件的约束总是层层向下传递:

样例1:Container只能从父组件继承约束,并向下施加,因此,子Container的宽高也继承自屏幕,并不是大小100的红色
Container(
      height: 100,
      width: 100,
      child:Container(color: Colors.red),
    ),

image.png 即使设置了constraints参数也不会向下施加约束,仍为全屏红色,constraints参数被忽略

Container(
      constraints: const BoxConstraints(
        minHeight: 50,
        maxHeight: 150,
        minWidth: 50,
        maxWidth: 150,
      ),
      child: Container(height: 100, width: 100, color: Colors.red),
    ),

image.png 同理,ConstrainedBox也只能从父组件(屏幕)继承约束,并向下施加,constraints参数被忽略

ConstrainedBox(
  constraints: const BoxConstraints(
    minWidth: 70,
    minHeight: 70,
    maxWidth: 150,
    maxHeight: 150,
  ),
  child: Container(color: red, width: 10, height: 10),
)

image.png

样例2: Center组件允许其子组件达到任意大小,所有ConstrainedBox最小宽高是70,向下施加,而Container要求宽高10小于ConstrainedBox最小70的要求,因此Container宽高是70

如果Container申请的宽高超过ConstrainedBox的最大宽高,那么实际能申请使用的宽高就是150

Center(
  child: ConstrainedBox(
    constraints: const BoxConstraints(
      minWidth: 70,
      minHeight: 70,
      maxWidth: 150,
      maxHeight: 150,
    ),
    child: Container(color: red, width: 10, height: 10),
  ),
)

image.png

样例3:UnconstrainedBox组件和Center组件一样可以允许子组件申请任意大小的宽高
UnconstrainedBox(
      child: Container(color: Colors.red, width: 100, height: 100),
    ),

image.png

ConstrainedBox可以约束子组件的最小和最大宽高,但是UnconstrainedBox则不能,超过屏幕宽高,则报错,left/right/top/bottom overflow,边界溢出。

UnconstrainedBox(
      child: Container(color: Colors.red, width: 1000, height: 100),
    ),

image.png

如果UnconstrainedBox中子组件申请无限大(double.infinity表示最大双精度数)的宽或高,则直接报运行时错误:BoxConstraints forces an infinite width,且不会渲染任何东西

UnconstrainedBox(
      child: Container(color: Colors.red, width: double.infinity, height: 100),
    ),

想要子组件超过屏幕大小,同时又不报边界溢出,可以使用OverflowBox代替UnconstrainedBox,但是必须指定最大最小宽度和高度,否则Container申请的大小将不会生效,而是填充满整个屏幕 注意此时Container申请的宽度是4000,而实际的宽度也是4000,只是因为屏幕无滚动所以被隐藏了

 OverflowBox(
      minHeight: 0,
      minWidth: 0,
      maxHeight: double.infinity,
      maxWidth: double.infinity,
      child: Container(color: Colors.red, width: 1000, height: 50),
    ),

image.png

注意: Center和UnconstraintBox都可约束子组件申请任意大小,不同的是Center组件只允许在屏幕的限制范围内,而UnconstraintBox则可以超出屏幕范围。

LimitedBox向子组件施加的约束,只能在无约束(UnconstraintBox)的父组件中有效

UnconstrainedBox(
  child: LimitedBox(
    maxWidth: 100,
    child: Container(
      color: Colors.red,
      width: double.infinity,
      height: 100,
    ),
  ),
)

image.png

如下示例中,LimitedBox如果放在有约束的Center(Center约束了屏幕大小)中将不会生效,由于Center约束屏幕大小,而Container的宽度是无限大,Container的宽度会充满屏幕。

Center(
  child: LimitedBox(
    maxWidth: 100,
    child: Container(
      color: Colors.red,
      width: double.infinity,
      height: 100,
    ),
  ),
)

image.png

样例4:FittedBox向子组件施加约束,使子组件和屏幕同样大小,并且会对子组件进行缩放以填充屏幕,但是要求子组件必须有大小(但不能无限大)或者固有大小(即intrinsic,列入Text组件会根据字数、字体大小计算本身的大小)。

如下,Container组件没有大小导致屏幕无渲染,不会报错

 FittedBox(
  child: Container(color: Colors.red),
)

image.png

如下,Container组件无限大导致屏幕无渲染,且会报错BoxConstraints forces an infinite height.

 FittedBox(
  child: Container(height:double.infinatly ,color: Colors.red),
)

如下,Container组件设置宽高都是50时,诡异的事情发生了,如果屏幕宽高一样(正方形),会充满屏幕

 FittedBox(
  child: Container(height:50 ,width:50 ,color: Colors.red),
)

image.png

如下,如果屏幕的宽高是长方形,时会以短边填充屏幕,不知道是什么情况,看了官方文档没有答案,后续读下源代码在做补充说明

image.png

如下,固有大小的子节点会被缩放,如Text

 const FittedBox(
  child: Text("我被放大了",
      textDirection: TextDirection.ltr,
  ),
)

image.png

如下,固有大小的子节点会被缩放,如Text的长度超过屏幕时

const FittedBox(
    child: Text(
      "我被缩小了,我缩小了吗,我的确被缩小了吗,我真的被缩小了吗,我肯定被缩小了吗,我确定 被缩小了吗,我确定以及肯定我们缩小了。",
      textDirection: TextDirection.ltr,
    ),
  )

image.png

注意:FittedBox在Center中,会根据子组件(必须固有大小intrinsic)调整自身大小以适应屏幕,这是和其他约束组件很有大不同,相当于子组件反向约束父组件