Flutter 布局(五)- LimitedBox、Offstage、OverflowBox、SizedBox详解

    LimitedBox,通过字面意思,也可以猜测出这个控件的作用,是限制类型的控件。这种类型的控件前面也介绍了不少了,这个是对最大宽高进行限制的控件。

    1.2 布局行为

    LimitedBox是将child限制在其设定的最大宽高中的,但是这个限定是有条件的。当LimitedBox最大宽度不受限制时,child的宽度就会受到这个最大宽度的限制,同理高度。

    1.3 继承关系

    1.4 示例代码

    1. children: <Widget>[
    2. color: Colors.red,
    3. width: 100.0,
    4. ),
    5. LimitedBox(
    6. maxWidth: 150.0,
    7. child: Container(
    8. color: Colors.blue,
    9. width: 250.0,
    10. ),
    11. ),
    12. ],
    13. )

    1.5 源码解析

    1. const LimitedBox({
    2. Key key,
    3. this.maxWidth = double.infinity,
    4. this.maxHeight = double.infinity,
    5. Widget child,
    6. })

    1.5.1 属性解析

    maxWidth:限定的最大宽度,默认值是double.infinity,不能为负数。

    maxHeight:同上。

    1.5.2 源码

    先不说其源码,单纯从其作用,前面介绍的SizedBox、ConstrainedBox都类似,都是通过强加到child的constraint,来达到相应的效果。

    我们直接看其计算constraint的代码

    1. minWidth: constraints.minWidth,
    2. maxWidth: constraints.hasBoundedWidth ? constraints.maxWidth : constraints.constrainWidth(maxWidth),
    3. minHeight: constraints.minHeight,
    4. maxHeight: constraints.hasBoundedHeight ? constraints.maxHeight : constraints.constrainHeight(maxHeight)

    LimitedBox只是改变最大宽高的限定。具体的布局代码如下:

    1. if (child != null) {
    2. size = constraints.constrain(child.size);
    3. } else {
    4. size = _limitConstraints(constraints).constrain(Size.zero);
    5. }

    根据最大尺寸,限制child的布局,然后将自身调节到child的尺寸。

    1.6 使用场景

    使用场景是不可能清楚了,光是找例子,就花了不少时间。Flutter的一些冷门控件,真的是除了官方的文档,啥材料都木有。谷歌说这个很有用,还是一脸懵逼。这种控件,也有其他的替代解决方案,LimitedBox可以达到的效果,ConstrainedBox都可以实现。

    2. Offstage

    2.1 简介

    Offstage的作用很简单,通过一个参数,来控制child是否显示,日常使用中也算是比较常用的控件。

    2.2 布局行为

    Offstage的布局行为完全取决于其offstage参数

    • 当offstage为true,当前控件不会被绘制在屏幕上,不会响应点击事件,也不会占用空间;
    • 当offstage为false,当前控件则跟平常用的控件一样渲染绘制;

    另外,当Offstage不可见的时候,如果child有动画,应该手动停掉,Offstage并不会停掉动画。

    1. Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > Offstage

    2.4 示例代码

    当点击切换按钮的时候,可以看到Offstage显示消失。

    2.5 源码解析

    1. const Offstage({ Key key, this.offstage = true, Widget child })

    2.5.1 属性解析

    2.5.2 源码

    我们先来看下Offstage的computeIntrinsicSize相关的方法:

    1. @override
    2. double computeMinIntrinsicWidth(double height) {
    3. if (offstage)
    4. return 0.0;
    5. return super.computeMinIntrinsicWidth(height);
    6. }

    可以看到,当offstage为true的时候,自身的最小以及最大宽高都会被置为0.0。

    接下来我们来看下其hitTest方法:

    1. @override
    2. bool hitTest(HitTestResult result, { Offset position }) {
    3. }

    当offstage为true的时候,也不会去执行。

    最后我们来看下其paint方法:

    1. @override
    2. void paint(PaintingContext context, Offset offset) {
    3. if (offstage)
    4. return;
    5. super.paint(context, offset);
    6. }

    当offstage为true的时候直接返回,不绘制了。

    到此,跟上面所说的布局行为对应上了。我们一定要清楚一件事情,Offstage并不是通过插入或者删除自己在widget tree中的节点,来达到显示以及隐藏的效果,而是通过设置自身尺寸、不响应hitTest以及不绘制,来达到展示与隐藏的效果。

    2.6 使用场景

    当我们需要控制一个区域显示或者隐藏的时候,可以使用这个场景。其实也有其他代替的方法,但是成本会高很多,例如直接在tree上插入删除,但是不建议这么做。

    3.1 简介

    OverflowBox这个控件,允许child超出parent的范围显示,当然不用这个控件,也有很多种方式实现类似的效果。

    3.2 布局行为

    当OverflowBox的最大尺寸大于child的时候,child可以完整显示,当其小于child的时候,则以最大尺寸为基准,当然,这个尺寸都是可以突破父节点的。最后加上对齐方式,完成布局。

    3.3 继承关系

    1. Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > OverflowBox

    3.4 示例代码

    当maxHeight大于height的时候,可以完全显示下来,当maxHeight小于height的时候,则不会会被隐藏掉

    构造函数如下:

    1. const OverflowBox({
    2. Key key,
    3. this.minWidth,
    4. this.maxWidth,
    5. this.minHeight,
    6. this.maxHeight,
    7. Widget child,
    8. })

    3.5.1 属性解析

    alignment:对齐方式。

    maxWidth:允许child的最大宽度。如果child宽度大于这个值,则按照最大宽度进行展示。

    minHeight:允许child的最小高度。如果child高度小于这个值,则按照最小高度进行显示。

    maxHeight:允许child的最大高度。如果child高度大于这个值,则按照最大高度进行展示。

    其中,最小以及最大宽高度,如果为null的时候,就取父节点的constraint代替。

    3.5.2 源码

    OverflowBox的源码很简单,我们先来看一下布局代码:

    1. if (child != null) {
    2. child.layout(_getInnerConstraints(constraints), parentUsesSize: true);
    3. alignChild();
    4. }

    如果child不为null,child则会按照计算出的constraints进行尺寸的调整,然后对齐。

    至于constraints的计算,则还是上面的逻辑,如果设置的有的话,就取这个值,如果没有的话,就拿父节点的。

    3.6 使用场景

    有时候设计图上出现的角标,会超出整个模块,可以使用OverflowBox控件。但我们应该知道,不使用这种控件,也可以完成布局,在最外面包一层,也能达到一样的效果。具体实施起来哪个比较方便,同学们自行取舍。

    4. SizedBox

    4.1 简介

    比较常用的一个控件,设置具体尺寸。

    4.2 布局行为

    SizedBox布局行为相对较简单:

    • child不为null时,如果设置了宽高,则会强制把child尺寸调到此宽高;如果没有设置宽高,则会根据child尺寸进行调整;
    • child为null时,如果设置了宽高,则自身尺寸调整到此宽高值,如果没设置,则尺寸为0;

    4.3 继承关系

    1. Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > SingleChildRenderObjectWidget > SizedBox

    4.4 示例代码

    1. Container(
    2. color: Colors.green,
    3. padding: const EdgeInsets.all(5.0),
    4. child: SizedBox(
    5. width: 200.0,
    6. height: 200.0,
    7. child: Container(
    8. color: Colors.red,
    9. width: 100.0,
    10. height: 300.0,
    11. ),
    12. ),
    13. )

    4.5 源码解析

    构造函数

    1. const SizedBox({ Key key, this.width, this.height, Widget child })

    4.5.1 属性解析

    width:宽度值,如果具体设置了,则强制child宽度为此值,如果没设置,则根据child宽度调整自身宽度。

    height:同上。

    4.5.2 源码

    SizedBox内部是通过RenderConstrainedBox来实现的。具体的源码就不解析了,总体思路是,根据宽高值算好一个constraints,然后强制应用到child上。

    4.6 使用场景

    笔者建了一个Flutter学习相关的项目,,里面包含了笔者写的关于Flutter学习相关的一些文章,会定期更新,文章中的代码也在这个项目中,欢迎大家关注。

    6. 参考

    1. LimitedBox class
    2. SizedBox class