compute[Min/Max]Intrinsic[Width/Height]()

Implement intrinsic sizing methods

The four intrinsic sizing methods answer hypothetical sizing questions without performing a real layout pass. They are called by IntrinsicWidth, IntrinsicHeight, and Table to measure render objects before constraints are known.

Each method receives the already-known dimension and returns a preferred size for the other:

MethodArgumentReturns
computeMinIntrinsicWidth(height) available height smallest width that avoids clipping content
computeMaxIntrinsicWidth(height) available height width beyond which extra space adds no value
computeMinIntrinsicHeight(width) available width smallest height that avoids clipping content
computeMaxIntrinsicHeight(width) available width height beyond which extra space adds no value

For most render objects, min and max intrinsic width are equal. They differ when content can reflow — a paragraph of text has a narrow min intrinsic width (the longest unbreakable word) and a wide max intrinsic width (the full text unwrapped on one line).

When measuring children from inside these methods, always call the public child.getMinIntrinsicWidth() / child.getMaxIntrinsicWidth() etc. — not the compute* variants directly.

Default Implementation#

All four methods return 0 by default. This is acceptable for render objects that only ever live inside a scrollable viewport.

To ensure that your render object is robust across many use-cases, you should implement all 4 methods.

Leaf — Fixed Size#

A render object with a fixed natural size ignores the argument and returns that size regardless of the available dimension.

static const double _width = 48;
static const double _height = 48;

@override
double computeMinIntrinsicWidth(double height) => _width;

@override
double computeMaxIntrinsicWidth(double height) => _width;

@override
double computeMinIntrinsicHeight(double width) => _height;

@override
double computeMaxIntrinsicHeight(double width) => _height;

Single Child — Passthrough#

Delegate directly to the child when the render object imposes no additional sizing logic of its own.

@override
double computeMinIntrinsicWidth(double height) =>
    child!.getMinIntrinsicWidth(height);

@override
double computeMaxIntrinsicWidth(double height) =>
    child!.getMaxIntrinsicWidth(height);

@override
double computeMinIntrinsicHeight(double width) =>
    child!.getMinIntrinsicHeight(width);

@override
double computeMaxIntrinsicHeight(double width) =>
    child!.getMaxIntrinsicHeight(width);

Single Child — With Padding#

Subtract padding from the argument before asking the child, then add it back to the result.

static const double _horizontal = 32; // left + right padding
static const double _vertical = 24;   // top + bottom padding

@override
double computeMinIntrinsicWidth(double height) =>
    child!.getMinIntrinsicWidth(math.max(0, height - _vertical)) + _horizontal;

@override
double computeMaxIntrinsicWidth(double height) =>
    child!.getMaxIntrinsicWidth(math.max(0, height - _vertical)) + _horizontal;

@override
double computeMinIntrinsicHeight(double width) =>
    child!.getMinIntrinsicHeight(math.max(0, width - _horizontal)) + _vertical;

@override
double computeMaxIntrinsicHeight(double width) =>
    child!.getMaxIntrinsicHeight(math.max(0, width - _horizontal)) + _vertical;

Column Layout (Children Stacked Vertically)#

Width is the maximum across all children. Height is the sum of all children's heights.

@override
double computeMinIntrinsicWidth(double height) {
  double maxWidth = 0;
  RenderBox? child = firstChild;
  while (child != null) {
    maxWidth = math.max(maxWidth, child.getMinIntrinsicWidth(double.infinity));
    child = (child.parentData! as ContainerBoxParentData<RenderBox>).nextSibling;
  }
  return maxWidth;
}

@override
double computeMaxIntrinsicWidth(double height) {
  double maxWidth = 0;
  RenderBox? child = firstChild;
  while (child != null) {
    maxWidth = math.max(maxWidth, child.getMaxIntrinsicWidth(double.infinity));
    child = (child.parentData! as ContainerBoxParentData<RenderBox>).nextSibling;
  }
  return maxWidth;
}

@override
double computeMinIntrinsicHeight(double width) {
  double totalHeight = 0;
  RenderBox? child = firstChild;
  while (child != null) {
    totalHeight += child.getMinIntrinsicHeight(width);
    child = (child.parentData! as ContainerBoxParentData<RenderBox>).nextSibling;
  }
  return totalHeight;
}

@override
double computeMaxIntrinsicHeight(double width) {
  double totalHeight = 0;
  RenderBox? child = firstChild;
  while (child != null) {
    totalHeight += child.getMaxIntrinsicHeight(width);
    child = (child.parentData! as ContainerBoxParentData<RenderBox>).nextSibling;
  }
  return totalHeight;
}

Row Layout (Children Side by Side)#

Width is the sum across all children. Height is the maximum across all children.

@override
double computeMinIntrinsicWidth(double height) {
  double totalWidth = 0;
  RenderBox? child = firstChild;
  while (child != null) {
    totalWidth += child.getMinIntrinsicWidth(height);
    child = (child.parentData! as ContainerBoxParentData<RenderBox>).nextSibling;
  }
  return totalWidth;
}

@override
double computeMaxIntrinsicWidth(double height) {
  double totalWidth = 0;
  RenderBox? child = firstChild;
  while (child != null) {
    totalWidth += child.getMaxIntrinsicWidth(height);
    child = (child.parentData! as ContainerBoxParentData<RenderBox>).nextSibling;
  }
  return totalWidth;
}

@override
double computeMinIntrinsicHeight(double width) {
  double maxHeight = 0;
  RenderBox? child = firstChild;
  while (child != null) {
    maxHeight = math.max(maxHeight, child.getMinIntrinsicHeight(double.infinity));
    child = (child.parentData! as ContainerBoxParentData<RenderBox>).nextSibling;
  }
  return maxHeight;
}

@override
double computeMaxIntrinsicHeight(double width) {
  double maxHeight = 0;
  RenderBox? child = firstChild;
  while (child != null) {
    maxHeight = math.max(maxHeight, child.getMaxIntrinsicHeight(double.infinity));
    child = (child.parentData! as ContainerBoxParentData<RenderBox>).nextSibling;
  }
  return maxHeight;
}