No history yet

Geometry and BoxConstraints

The Layout Negotiation

In Flutter, widgets don't just pick a size. They negotiate. This happens in a strict, three-pass process. The golden rule is simple: Constraints go down. Sizes go up. Parent sets position.

A parent widget tells its child the minimum and maximum width and height it can be. This set of four numbers is a BoxConstraints. The child then decides on a size that fits those constraints and reports that size back up to the parent. Let's see how this plays out with a Container.

Tight vs Loose Constraints

Constraints come in two flavors: tight and loose.

Tight constraints force an exact size. This happens when minWidth == maxWidth and minHeight == maxHeight.

Loose constraints offer a range of sizes. This happens when the min and max values are different.

Consider a Container with a specified width and height. When its parent passes down loose constraints, the Container respects its own size properties. But if the parent passes down tight constraints, the Container must ignore its own width and height and obey its parent. The parent always wins.

```dart
// Parent provides tight constraints (the screen size)
Center(
  // Container wants to be 100x100, but Center
  // forces it to be as big as possible.
  child: Container( 
    width: 100, 
    height: 100, 
    color: Colors.blue,
  ), // This Container will fill the screen.
)

Now, let's see what happens if the parent offers flexibility.

```dart
// Parent provides loose constraints (0 to screen size)
Align(
  // Container is free to choose its size within the
  // parent's bounds. It chooses 100x100.
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
  ), // This Container will be 100x100.
)

Children and Unbounded Space

A Container's behavior also changes based on whether it has a child. Without a child, a Container with no size constraints will try to be as large as possible. If you give it a child, it will shrink to fit the child's size.

ScenarioContainer with width/heightContainer without sizeContainer with child
Tight ParentIgnores own size, matches parentMatches parent's sizeMatches parent's size
Loose ParentUses its own width/heightExpands to max parent sizeShrinks to child's size

This becomes critical in widgets like Column or ListView. These widgets provide infinite (or unbounded) height to their children along their main axis. If you place a Container that tries to be as large as possible inside a Column, Flutter throws an error. The Container wants infinite height, but infinite size is not a valid layout.

You'll see the dreaded "BoxConstraints forces an infinite height" error. This means a widget that wants to expand is inside another widget that gives it unlimited space to do so.

The fix is to give the child a bounded constraint. You can wrap the expanding widget in another widget that provides a specific size, like SizedBox or Expanded. Expanded is special: it tells its child to take up a specific portion of the remaining space, turning an infinite constraint into a finite, tight one. This resolves the conflict in the layout negotiation.

Understanding that layout is a negotiation governed by strict rules is the key to solving most of Flutter's sizing problems. When something looks wrong, trace the flow: what constraints is the parent passing down, and what size is the child trying to be?