为什么该列占据其父级(容器)的整个宽度

aks*_*hay 6 dart flutter flutter-layout

  1. 我在容器内有一列
  2. 容器的宽度设置为300
  3. 该列有一个文本子项
  4. 现在,通常,列宽将是其最宽子项的宽度。在这种情况下,它只有一个文本子项,因此列的宽度应该是文本子项的宽度
  5. 但是,该列扩展到父级的整个宽度为 300,即宽度为 300 的容器父级
class TestPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: EdgeInsets.all(10),
          child: Container(
            width: 300,
            color: Colors.orangeAccent,
            child: Column(
              // mainAxisSize: MainAxisSize.min,
              children: [
                Text('Hi', style: TextStyle(fontSize: 50)),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 我们可以通过在图像中看到子项居中对齐(这是默认的横轴对齐)来观察到该列正在扩展到其父项的整个宽度。

在此输入图像描述

我浏览了容器文档,但无法弄清楚为什么会发生这种情况。有人可以解释为什么该列占据其父级的全宽吗?

Ale*_*sky 5

列占据容器的整个宽度,因为容器强制它这样做。如果您指定 Container 的宽度,那么 Container 基本上将在后台使用 ConstrainedBox,对其子级进行严格约束。在您的情况下,请输入minWidth = 300

如果您希望 Column 尽可能窄,您应该使用 UnconstrainedBox 小部件包装它,该小部件将接受 Container 自身的严格约束,并使 Column 具有其“自然”大小。如果仍然希望列尽可能高,则需要指定constrainedAxis: UnconstrainedBox 的 Axis.vertical 属性


Gui*_*oux 1

为了更好地理解Container这里的工作原理,您可以在 flutter 源中找到该小部件的实现:

Container({
  Key? key,
  this.alignment,
  this.padding,
  this.color,
  this.decoration,
  this.foregroundDecoration,
  double? width,
  double? height,
  BoxConstraints? constraints,
  this.margin,
  this.transform,
  this.transformAlignment,
  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(decoration != null || clipBehavior == Clip.none),
       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);
Run Code Online (Sandbox Code Playgroud)

有趣的部分是属性constraints

constraints =
  (width != null || height != null)
    ? constraints?.tighten(width: width, height: height)
      ?? BoxConstraints.tightFor(width: width, height: height)
    : constraints
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,如果您为width和/或height属性赋予一个值,它将BoxConstraints对其子部件应用 a ,强制您的子部件Column遵守此约束。

更新:该alignment属性如何运作?

如果您查看该Container小部件的源代码,您会在其方法中找到它build

Widget build(BuildContext context) {
  Widget? current = child;

  // ...

  if (alignment != null)
    current = Align(alignment: alignment!, child: current);

  // ...
}
Run Code Online (Sandbox Code Playgroud)

这意味着通过提供非空alignment属性,您的child小部件将被包装在Align小部件内。现在让我们看一下Align小部件的实现,更准确地说是它的createRenderObject()方法:

@override
RenderPositionedBox createRenderObject(BuildContext context) {
  return RenderPositionedBox(
    alignment: alignment,
    widthFactor: widthFactor,
    heightFactor: heightFactor,
    textDirection: Directionality.maybeOf(context),
  );
}
Run Code Online (Sandbox Code Playgroud)

因此,通过提供一个Align小部件,它将创建一个RenderPositionedBox让我们也通过该方法来看看它的实现performLayout()

@override
void performLayout() {
  final BoxConstraints constraints = this.constraints;
  final bool shrinkWrapWidth = _widthFactor != null || constraints.maxWidth == double.infinity;
  final bool shrinkWrapHeight = _heightFactor != null || constraints.maxHeight == double.infinity;

  if (child != null) {
    child!.layout(constraints.loosen(), parentUsesSize: true);
    size = constraints.constrain(Size(
      shrinkWrapWidth ? child!.size.width * (_widthFactor ?? 1.0) : double.infinity,
      shrinkWrapHeight ? child!.size.height * (_heightFactor ?? 1.0) : double.infinity,
    ));
    alignChild();
  } else {
    size = constraints.constrain(Size(
      shrinkWrapWidth ? 0.0 : double.infinity,
      shrinkWrapHeight ? 0.0 : double.infinity,
    ));
  }
}
Run Code Online (Sandbox Code Playgroud)

在那里,您可以根据其父项的和BoxConstraints来应用一些内容。childmaxWidthmaxHeight