将Container比做成Flutter中的div并不恰当,但这并不妨碍前端同学用Container做为起点来学习。
布局表现
-
如果没有子节点、没有设置width、height以及constraints,并且父节点提供了unbounded的限制,Container会将自身调整到足够小。
-
如果没有子节点、对齐方式(alignment),但是提供了width、height或者constraints,那么Container会根据自身以及父节点的限制,将自身调节到足够小。
-
如果没有子节点、width、height、constraints以及alignment,但是父节点提供了bounded限制,那么Container会按照父节点的限制,将自身调整到足够大。
-
如果有子节点以及alignment,父节点提供了unbounded限制,那么Container将会调节自身尺寸来包住child;
-
如果有有子节点以及alignment,并且父节点提供了bounded限制,那么Container会将自身调整的足够大(在父节点的范围内),然后将child根据alignment调整位置;
-
如果有child,但是没有width、height、constraints以及alignment,Container会将父节点的constraints传递给child,并且根据child调整自身
属性
key:Container唯一标识符,用于查找更新。
alignment:控制child的对齐方式,如果container或者container父节点尺寸大于child的尺寸,这个属性设置会起作用,有很多种对齐方式。
padding:decoration内部的空白区域,如果有child的话,child位于padding内部。padding与margin的不同之处在于,padding是包含在content内,而margin则是外部边界,设置点击事件的话,padding区域会响应,而margin区域不会响应。
color:用来设置container背景色,如果foregroundDecoration设置的话,可能会遮盖color效果。
decoration:绘制在child后面的装饰,设置了decoration的话,就不能设置color属性,否则会报错,此时应该在decoration中进行颜色的设置。
foregroundDecoration:绘制在child前面的装饰。
width:container的宽度,设置为double.infinity可以强制在宽度上撑满,不设置,则根据child和父节点两者一起布局。
height:container的高度,设置为double.infinity可以强制在高度上撑满。
constraints:添加到child上额外的约束条件。
margin:围绕在decoration和child之外的空白区域,不属于内容区域。
transform:设置container的变换矩阵,类型为Matrix4。
child:container中的内容widget
源码
// flutter/lib/src/widgets/container.dart
class Container extends StatelessWidget {
Container({
Key key,
this.alignment,
this.padding,
this.color,
this.decoration,
this.foregroundDecoration,
double width,
double height,
BoxConstraints constraints,
this.margin,
this.transform,
this.child,
this.clipBehavior = Clip.none,
}) : assert(margin == null || margin.isNonNegative),
assert(padding == null || padding.isNonNegative),
assert(decoration == null || decoration.debugAssertIsValid()),
assert(constraints == null || constraints.debugAssertIsValid()),
assert(clipBehavior != null),
assert(
color == null || decoration == null,
'Cannot provide both a color and a decoration\n'
'To provide both, use "decoration: BoxDecoration(color: color)".'),
constraints = (width != null || height != null)
? constraints?.tighten(width: width, height: height) ??
BoxConstraints.tightFor(width: width, height: height)
: constraints,
super(key: key);
final Widget child;
// child 元素在 Container 中的对齐方式
final AlignmentGeometry alignment;
// 填充内边距
final EdgeInsetsGeometry padding;
// 颜色
final Color color;
// 背景装饰
final Decoration decoration;
// 前景装饰
final Decoration foregroundDecoration;
// 布局约束
final BoxConstraints constraints;
// 外边距
final EdgeInsetsGeometry margin;
// 绘制容器之前要应用的变换矩阵
final Matrix4 transform;
// decoration 参数具有 clipPath 时的剪辑行为
final Clip clipBehavior;
EdgeInsetsGeometry get _paddingIncludingDecoration {
if (decoration == null || decoration.padding == null) return padding;
final EdgeInsetsGeometry decorationPadding = decoration.padding;
if (padding == null) return decorationPadding;
return padding.add(decorationPadding);
}
@override
Widget build(BuildContext context) {
Widget current = child;
if (child == null && (constraints == null || !constraints.isTight)) {
current = LimitedBox(
maxWidth: 0.0,
maxHeight: 0.0,
child: ConstrainedBox(constraints: const BoxConstraints.expand()),
);
}
if (alignment != null)
current = Align(alignment: alignment, child: current);
final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration;
if (effectivePadding != null)
current = Padding(padding: effectivePadding, child: current);
if (color != null) current = ColoredBox(color: color, child: current);
if (decoration != null)
current = DecoratedBox(decoration: decoration, child: current);
if (foregroundDecoration != null) {
current = DecoratedBox(
decoration: foregroundDecoration,
position: DecorationPosition.foreground,
child: current,
);
}
if (constraints != null)
current = ConstrainedBox(constraints: constraints, child: current);
if (margin != null) current = Padding(padding: margin, child: current);
if (transform != null)
current = Transform(transform: transform, child: current);
if (clipBehavior != Clip.none) {
current = ClipPath(
clipper: _DecorationClipper(
textDirection: Directionality.of(context), decoration: decoration),
clipBehavior: clipBehavior,
child: current,
);
}
return current;
}
}