手记

Flutter 67: 图解基本约束 Box (二)

      小菜继续学习约束 Box 的各类应用;

UnconstrainedBox

源码分析

class UnconstrainedBox extends SingleChildRenderObjectWidget {
    const UnconstrainedBox({
        Key key,
        Widget child,
        this.textDirection,                 // 文字方向
        this.alignment = Alignment.center,  // 对齐方式
        this.constrainedAxis,               // 是否保留约束轴方向
    })
}

      分析源码可得,UnconstrainedBox 继承自 SingleChildRenderObjectWidget,与 ConstrainedBox 效果相反,给子 Widget 提供不加限制的空间;

案例尝试

      UnconstrainedBox 不会对子 Widget 进行约束限制,按照其子 Widget 大小进行绘制;小菜理解为去除父 Widget 的限制,让子 Widget 完全绘制;

1. alignment

      用于子 Widget 的对齐方向,可以通过 AlignmentAlignmentDirectional 进行调整所在位置;其中 AlignmentDirectional start/y 范围是 [-1.0, 1.0]

2. textDirection

      当 alignment 使用 AlignmentDirectional 方式设置对齐方式时,textDirection 用于从左到右或从右到左的起始方向;

return Container(height: 180, width: 180, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(constrainedAxis: null,
        alignment: AlignmentDirectional(-1.0, 1.0), textDirection: TextDirection.ltr, 
        child: Container(width: 90, height: 90, color: Colors.green.withOpacity(0.6))));
return Container(height: 180, width: 180, color: Colors.redAccent.withOpacity(0.4),
    child: UnconstrainedBox(constrainedAxis: null,
        alignment: AlignmentDirectional(-1.0, -1.0), textDirection: TextDirection.rtl,
        child: Container(width: 100, height: 100, color: Colors.purple.withOpacity(0.6))));

3. constrainedAxis

      作用于是否保留约束的轴方向,若不设置或设置为 null 则横向或纵向均不保留约束;若设置为 vertical 则保留其父类纵向约束;设置为 horizontal 则保留其父类横向约束;

return Container(height: 100, width: 360, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(alignment: Alignment.center, constrainedAxis: null,
        child: Container(width: 80, height: 80, color: Colors.green.withOpacity(0.6))));
return Container(height: 100, width: 360, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(alignment: Alignment.center, constrainedAxis: Axis.vertical,
        child: Container(width: 100, height: 300, color: Colors.green.withOpacity(0.6))));
return Container(height: 100, width: 360, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(alignment: Alignment.topRight, constrainedAxis: Axis.horizontal,
        child: Container(width: 100, height: 300, color: Colors.green.withOpacity(0.6))));
return Container(height: 100, width: 360, color: Colors.blueAccent.withOpacity(0.4),
    child: UnconstrainedBox(alignment: Alignment.topLeft, constrainedAxis: null,
        child: Container(width: 100, height: 300, color: Colors.green.withOpacity(0.6))));

LimitedBox

源码分析

class LimitedBox extends SingleChildRenderObjectWidget {
  const LimitedBox({
    Key key,
    this.maxWidth = double.infinity,    // 最大宽度
    this.maxHeight = double.infinity,   // 最大高度
    Widget child,
  })
}

      分析源码可知,LimitedBox 主要是在不受父 Widget 限制时,通过 maxHeight / maxWidth 对子 Widget 的约束,且 maxHeight / maxWidth 必须 >= 0.0;

案例尝试

      小菜分如下几个场景进行尝试

  1. LimitedBoxWidget 无限制,子 Widget 宽高小于约束最大宽高;
return Container(child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 80, height: 80, color: Colors.purple.withOpacity(0.4))));

  1. LimitedBoxWidget 无限制,子 Widget 宽高大于约束最大宽高;
return Container(child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 160, height: 160, color: Colors.orange.withOpacity(0.4))));

  1. LimitedBoxWidget 有限制时;无论 LimitedBox 设置限制最大宽高和子 Widget 宽高,均以父 Widget 宽高为准;
return Container(width: 200, height: 80, child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 160, height: 160, color: Colors.orange.withOpacity(0.4))));

FractionallySizedBox

源码分析

class FractionallySizedBox extends SingleChildRenderObjectWidget {
  const FractionallySizedBox({
    Key key,
    this.alignment = Alignment.center,  // 对齐方式
    this.widthFactor,                   // 宽度因子
    this.heightFactor,                  // 高度因子
    Widget child,
  })
}

      分析源码可知,FractionallySizedBox 可以通过对齐方式和设置宽高因子并结合父 Widget 宽高来约束子 Widget;采用宽高因子使用更加灵活;

案例尝试

1. alignment

      与其他组件相同,通用于子 Widget 的对齐方向;

2. widthFactor

      宽度因子,若不为 null 则通过父 Widget 宽度占比来约束子 Widget 宽度;若为 null 按照父 Widget 宽度填充;

3. heightFactor

      高度因子,与 widthFactor 使用相同;

return Container(color: Colors.blueAccent.withOpacity(0.4), width: 100, height: 100,
    child: FractionallySizedBox(alignment: Alignment.center, widthFactor: 0.5, heightFactor: 0.5,
        child: Container(width: 50, height: 80, color: Colors.orange.withOpacity(0.6))));
return Container(color: Colors.blueAccent.withOpacity(0.4), width: 100, height: 100,
    child: FractionallySizedBox(alignment: Alignment.center, widthFactor: 0.5, heightFactor: null,
        child: Container(width: 200, height: 200, color: Colors.orange.withOpacity(0.6))));
return Container(color: Colors.blueAccent.withOpacity(0.4), width: 100, height: 100,
    child: FractionallySizedBox(alignment: Alignment.center, widthFactor: 1.5, heightFactor: 0.6,
        child: Container(color: Colors.orange.withOpacity(0.6))));
return Container(color: Colors.blueAccent.withOpacity(0.4), width: 100, height: 100,
    child: FractionallySizedBox(alignment: AlignmentDirectional(-0.15, -0.15), widthFactor: 0.5, heightFactor: 0.5,
        child: Container(color: Colors.orange.withOpacity(0.6))));

FittedBox

源码分析

class FittedBox extends SingleChildRenderObjectWidget {
  const FittedBox({
    Key key,
    this.fit = BoxFit.contain,          // 填充方式
    this.alignment = Alignment.center,  // 对齐方式
    Widget child,
  })
}

      分析源码可知,FittedBox 主要通过 fit 填充方式和 alignment 对齐方式对子 Widget 进行约束;且 fit / alignment 不可为空,对于图片的裁剪很有效;

案例尝试

      FittedBox 主要是通过 BoxFit 填充方式与 alignment 对齐方式共同约束子 Widget

  1. BoxFit.fill 通过子 Widget 拉伸或压缩填充满父 Widget
  2. BoxFit.contain 通过子 Widget 比例拉伸或压缩,直到宽或高一边填充父 Widget
  3. BoxFit.cover 以子 Widget 宽或高填充父 Widget,剩余一边若超过父 Widget 对应边则裁切;
  4. BoxFit.fitWidth 通过子 Widget 以宽为基准填充父 Widget,若高度超出会被裁切,子 Widget 不拉伸或压缩;
  5. BoxFit.fitHeight 通过子 Widget 以高为基准填充父 Widget,若宽度超出会被裁切,子 Widget 不拉伸或压缩;
  6. BoxFit.noneWidget 不拉伸或压缩,若超出父 Widget 则被裁切;
  7. BoxFit.scaleDown 若子 Widget 可以完全放在父 Widget 中则与 BoxFit.none 效果一致;若子 Widget 不能完全放在父 Widget 中则与 BoxFit.contain 效果一致;
return Container(width: 100, height: 100, color: Colors.blueAccent.withOpacity(0.4),
    child: FittedBox(fit: BoxFit.cover, alignment: Alignment.topCenter, child: Image.asset("images/icon_hzw02.jpg")));
return Container(width: 100, height: 100, color: Colors.blueAccent.withOpacity(0.4),
    child: FittedBox(fit: BoxFit.fill, alignment: Alignment.topCenter, child: Image.asset("images/icon_hzw02.jpg")));
return Container(width: 100, height: 100, color: Colors.blueAccent.withOpacity(0.4),
    child: FittedBox(fit: BoxFit.fitHeight, alignment: Alignment.topCenter, child: Image.asset("images/icon_hzw02.jpg")));
return Container(width: 100, height: 100, color: Colors.blueAccent.withOpacity(0.4),
    child: FittedBox(fit: BoxFit.none, alignment: Alignment.center, child: Image.asset("images/icon_hzw02.jpg")));


      Flutter 提供了多种约束 Box 方式,基本都是继承自 SingleChildRenderObjectWidget,每种 Box 有各自特点,合理利用可以大大提高开发效率;小菜对 Box 的学习还不完整,有错误的地方请多多指导!

来源: 阿策小和尚

0人推荐
随时随地看视频
慕课网APP