小菜继续学习约束 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 的对齐方向,可以通过 Alignment 或 AlignmentDirectional 进行调整所在位置;其中 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;
案例尝试
小菜分如下几个场景进行尝试
- LimitedBox 父 Widget 无限制,子 Widget 宽高小于约束最大宽高;
return Container(child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 80, height: 80, color: Colors.purple.withOpacity(0.4))));
- LimitedBox 父 Widget 无限制,子 Widget 宽高大于约束最大宽高;
return Container(child: LimitedBox(maxWidth: 100, maxHeight: 100, child: Container(width: 160, height: 160, color: Colors.orange.withOpacity(0.4))));
- LimitedBox 父 Widget 有限制时;无论 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;
- BoxFit.fill 通过子 Widget 拉伸或压缩填充满父 Widget;
- BoxFit.contain 通过子 Widget 比例拉伸或压缩,直到宽或高一边填充父 Widget;
- BoxFit.cover 以子 Widget 宽或高填充父 Widget,剩余一边若超过父 Widget 对应边则裁切;
- BoxFit.fitWidth 通过子 Widget 以宽为基准填充父 Widget,若高度超出会被裁切,子 Widget 不拉伸或压缩;
- BoxFit.fitHeight 通过子 Widget 以高为基准填充父 Widget,若宽度超出会被裁切,子 Widget 不拉伸或压缩;
- BoxFit.none 子 Widget 不拉伸或压缩,若超出父 Widget 则被裁切;
- 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 的学习还不完整,有错误的地方请多多指导!
来源: 阿策小和尚