Container

一个集绘制、定位和大小调整于一体的容器组件

Container首先会用padding将内部子组件包裹起来,如果在decoration中设置了边框,那么padding还将算上边框。之后如果height或者width不为空的话,还将对内部范围添加额外根据height或者width设定的约束。最后根据margin设置的大小给Container外部包裹对应大小的外边框。

在绘制过程中,Container会先应用给定的变化,然后根据decoration中的设置去绘制装饰层填充范围。再然后就会去绘制子组件,最后根据foregroundDecoration绘制前景装饰层填充范围。

在没有子组件的时候,Container会尽量撑满空间,除非遇到了无限宽高限制的情况-这时候它就会反过来尽量缩小。而内部有子组件的Container则会根据子组件的大小进行自适应。但是如果构造器里如果传入了widthheightconstraints参数,都将覆盖自身的这些默认行为。

一般情况下,Container是不会响应点击事件的(它永远返回false)。在设置了color属性的情况下,点击就会交由ColoredBox进行处理(它永远返回true)。要是设置了decoration或者foregroundDecoration属性,那么就会交由Decoration.hitTest方法来进行响应处理。

布局行为

因为Container集成了很多其他自带布局功能的Widget,所以它的布局行为非常的复杂!

总的来说,Container布局策略是按照如下优先级来的:

  1. 进行对齐
  2. 根据子组件调整尺寸
  3. 根据宽高和constraints限制进行调整
  4. 撑满父组件
  5. 尽可能缩小自己

对应的具体操作就是:

  1. 如果Container没有子组件,也没有设置宽高,也没有约束条件,父组件也没有给约束限制,这时候Container就会尽可能将自己缩小
  2. 如果Container没有子组件,也没有设置对齐方式,但是指定了宽高或者constraints,这时候Container就会在自身约束和父级约束的共同作用下,将自己缩到最小
  3. 如果Container没有子组件,没有对齐方式,没有高度宽度自身约束,但是父组件设置了约束的话,那么Container会根据父组件设置的约束来撑满自己
  4. 如果Container设置了对齐方式,而父组件给了无限制约束的话,那么Container会主动调整自己的尺寸去包裹住子组件
  5. 如果Container设置了对齐方式,而父组件给了固定约束的话,那么Container会先撑满自己,再按照对齐方式去调整子组件在Container中的位置
  6. 如果Container没有设置尺寸,约束和对齐方式,但是有子组件,那么Container就会把父组件的约束条件给子组件,自己的大小跟着子组件来自适应
  7. marginpadding也会影响布局效果,它们的作用就是辅助上面那些规则。decoration设置可能会偷偷加大padding(比如BoxDecoration的边框会占据padding的空间)

更多关于盒子布局模型的内容,可以参看BoxConstraints的文档。

例子

例子A

Center(
  child: Container(
    margin: const EdgeInsets.all(10.0),
    color: Colors.amber[600],
    width: 48.0,
    height: 48.0,
  ),
)

按照上面的规则,Container没有子组件也没有设置对齐方式,但是设置了宽高,Center没有设置宽高,则CenterContainer的约束变为松约束(0<=w<=屏幕宽度,0<=h<=屏幕高度),那么Container将会遵守自身宽高约束变为48 * 48的琥珀色方块,然后再设置了10外边距,再因为外部包裹了Center组件,Container会处于父组件的中间。

例子B

Container(
  constraints: BoxConstraints.expand(
    height: Theme.of(context).textTheme.headlineMedium!.fontSize! * 1.1 + 200.0,
  ),
  padding: const EdgeInsets.all(8.0),
  color: Colors.blue[600],
  alignment: Alignment.center,
  transform: Matrix4.rotationZ(0.1),
  child: Text('Hello World',
    style: Theme.of(context)
        .textTheme
        .headlineMedium!
        .copyWith(color: Colors.white)),
)

Container使用了BoxConstraints.expand且没有设置width,那么width会扩展到外部最大的宽度(通常为屏幕宽度),height则设置为中号标题字体大小的1.1倍加上200。设置内边距为8,颜色为蓝色,并围绕Z轴进行旋转。设置对齐方式为居中对齐,这样子组件就被放置在Container的中间,然后渲染一个Text子组件,设置内容和样式。

构造函数

Container.new({
  Key? key, 
  AlignmentGeometry? alignment, 
  EdgeInsetsGeometry? padding, 
  Color? color, 
  Decoration? decoration, 
  Decoration? foregroundDecoration, 
  double? width, 
  double? height, 
  BoxConstraints? constraints, 
  EdgeInsetsGeometry? margin, 
  Matrix4? transform, 
  AlignmentGeometry? transformAlignment, 
  Widget? child, 
  Clip clipBehavior = Clip.none
})

参数

参数名参数类型解释
alignmentAlignmentGeometryContainer内放置child的对齐方式
childWidget?Container的子组件
clipBehaviorClipContainer的裁剪行为
colorColor?Container填充的颜色
constraintsBoxConstraints?对于自身和子组件的额外约束
decorationDecoration?Container的装饰
foregroundDecorationDecoration?Container的前景装饰 (decorationchild后面,foregroundDecorationchild前面)
marginEdgeInsetsGeometry?外边距
paddingEdgeInsetsGeometry?内边距
transformMatrix4?形状转换
transformAlignmentAlignmentGeometry?如果指定了形状变化,设置原点相对于容器大小的对齐方式