skip to content

Box Layout Model

Flutter lays out in one pass: constraints go down, sizes go up and the parent sets position, through flex, stack, responsive and aspect widgets. Interviewers probe overflow and unbounded-size errors.

part ofFlutteroverview, primer and where to startread it →
on this pageshow

explore

questions

26

In Flutter, what are the main axis and cross axis of a Row and a Column, and which properties align children along each?

level: juniorimportance: must knowfreq 82%

answer

  1. direction of the children run
  2. Row horizontal, Column vertical
  3. mainAxisAlignment defaults to start
  4. crossAxisAlignment defaults to center
  5. mainAxisSize defaults to max

basics

~20 s

The main axis is the direction children are laid out: horizontal for Row, vertical for Column; the cross axis is perpendicular. mainAxisAlignment (default start) and mainAxisSize (default max) act on the main axis, crossAxisAlignment (default center) on the cross axis.

solid answer

~40 s

`Row` and `Column` are both `Flex` with a fixed `direction`. The **main axis** is the one children are placed along — horizontal for `Row`, vertical for `Column` — and the **cross axis** is perpendicular. Three properties matter: `mainAxisAlignment` places children and free space along the main axis (`start` by default, plus `end`, `center`, `spaceBetween`, `spaceAround`, `spaceEvenly`); `crossAxisAlignment` positions each child across (`center` by default, plus `start`, `end`, `stretch`, `baseline`); `mainAxisSize` decides whether the widget takes all available main-axis space (`max`, the default) or only what its children need (`min`). The classic slip is swapping axes: to centre children horizontally in a `Column` you set `crossAxisAlignment`, not `mainAxisAlignment`.

code

dart · 23 lines
dart
import 'package:flutter/material.dart';

class NutritionLabel extends StatelessWidget {
  const NutritionLabel({super.key});

  @override
  Widget build(BuildContext context) {
    return const Column(
      mainAxisSize: MainAxisSize.min, // hug the rows
      crossAxisAlignment: CrossAxisAlignment.stretch, // rows span the label width
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [Text('Calories'), Text('230')],
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [Text('Total fat'), Text('8 g')],
        ),
      ],
    );
  }
}

go deeper

for a junior

Recall which axis is main for Row and for Column, the three properties and their defaults: start, center and max.

for a middle

Explain that mainAxisAlignment only distributes free space and that the cross extent comes from the largest child.

for a senior

Predict layouts from the axis model without trial and error, and spot when a flex child or MainAxisSize.min has removed the free space an alignment relies on.

for a principal

Encourage axis-based vocabulary in reviews and shared components so Row and Column layouts stay consistent across a large codebase.

## Two widgets, one layout `Row` and `Column` are thin subclasses of **`Flex`**. `Row` fixes `direction: Axis.horizontal`; `Column` fixes `direction: Axis.vertical`. Everything else — alignment, sizing, spacing, flexible children — is shared, and it is all described in terms of two axes rather than width and height. - The **main axis** is the direction the children run in. - The **cross axis** is perpendicular to it. | Widget | Main axis | Cross axis | Main-axis size means | Cross-axis size means | |---|---|---|---|---| | `Row` | horizontal | vertical | width | height | | `Column` | vertical | horizontal | height | width | Once you think in axes, the same property works for both widgets and you stop memorising 'which one is horizontal for Column'. ## mainAxisAlignment: placing children and free space `mainAxisAlignment` controls where children sit along the main axis and how any **free space** — main-axis space the children did not use — is distributed. The values: 1. `start` (the default) — children packed at the start, free space at the end. 2. `end` — packed at the end. 3. `center` — packed in the middle, free space split before and after. 4. `spaceBetween` — free space divided evenly between children, none at the ends. 5. `spaceAround` — half-size gaps at the ends, full gaps between. 6. `spaceEvenly` — equal gaps between children and at both ends. If there is no free space, because the children fill the axis or a flexible child took it, `mainAxisAlignment` has nothing to distribute and appears to do nothing. ## crossAxisAlignment: positioning across `crossAxisAlignment` places each child across the run. The values are `start`, `end`, `center` (the default), `stretch` and `baseline`. - `start`/`end`/`center` move a child within the widget's cross extent. - `stretch` forces every child to fill the cross axis by giving it tight cross-axis constraints. - `baseline` lines up text baselines in a `Row` and needs a `textBaseline` argument. The cross extent of a `Row` or `Column` is the largest cross size among its children, within its own constraints. So a `Column` of three labels is as wide as its widest label, and `CrossAxisAlignment.start` left-aligns the narrower ones inside that width. ## mainAxisSize: how much of the main axis to take `mainAxisSize` decides the widget's own main-axis extent after the children are sized: - **`MainAxisSize.max`** (default): as large as the incoming constraints allow. A `Column` in a screen body is as tall as the body, even with two short children. - **`MainAxisSize.min`**: the sum of the children's sizes (and any spacing), within the constraints. Use it for a `Column` inside a `Card` or dialog that should hug its content. `mainAxisSize` and `mainAxisAlignment` interact: with `min`, there is usually no free space, so `center` or `spaceBetween` have nothing to spread. ## A nutrition-label row, both ways A nutrition label is a `Column` of rows, each row a nutrient name, a daily-value bar and an amount: - The outer `Column` uses `crossAxisAlignment: CrossAxisAlignment.stretch` so every row spans the label's width, and `mainAxisSize: MainAxisSize.min` so the label is only as tall as its rows. - Each `Row` uses `mainAxisAlignment: MainAxisAlignment.spaceBetween` when it has just a name and an amount, pushing them to opposite edges. - Aligning the amount's text with the name's text is a cross-axis job for that `Row` (`crossAxisAlignment`), not a main-axis one. ## Common mistakes - Setting `mainAxisAlignment: MainAxisAlignment.center` on a `Column` and expecting horizontal centring. - Expecting `spaceBetween` to work in a `Row` whose `Expanded` child already consumed the free space. - Leaving a `Column` at `MainAxisSize.max` inside a dialog and wondering why the dialog is full height.

  • In a Flutter Row with an Expanded child, why does mainAxisAlignment: MainAxisAlignment.center seem to do nothing?
    `mainAxisAlignment` only distributes free space: main-axis space the children did not use. An `Expanded` child is forced to fill all the space left after the inflexible children, so the free space is zero and there is nothing to centre. Remove the flex, use `Flexible` with a loose fit, or let the Row use `MainAxisSize.min`.
  • How wide is a Flutter Column whose children are three Text labels of different lengths?
    A `Column`'s cross extent is the largest cross size among its children, within its own constraints, so it is as wide as the widest label (unless its constraints force more, for example tight width). `crossAxisAlignment` then positions the narrower labels inside that width; `stretch` instead forces every child to the maximum width available.

saying these in an interview costs you the question

  • In a Column, mainAxisAlignment centres the children horizontally.
  • Row's default crossAxisAlignment is start, so children sit at the top.
  • MainAxisSize.min makes a Column shrink on both axes.
  • spaceBetween still spreads children when an Expanded child is present.
  • Row and Column are unrelated widgets with different alignment properties.
open as a page

In Flutter, what does the SafeArea widget do, and which of its parameters let you tune the padding it applies?

level: juniorimportance: must knowfreq 58%

basics

~20 s

SafeArea pads its child by the MediaQuery padding so system UI such as the status bar, notch and home indicator does not cover it. Per-side booleans switch sides off, minimum sets a floor, and maintainBottomViewPadding keeps the bottom inset while the keyboard is open.

open as a page

In Flutter layout, what does the rule 'constraints go down, sizes go up, parent sets position' mean for a widget?

level: juniorimportance: must knowfreq 80%

basics

~20 s

Each parent passes BoxConstraints (min and max width and height) down, each child picks a size inside them and reports it up, and the parent then places the child. A widget cannot choose its position or a size outside its constraints.

open as a page

In Flutter, how does a Stack decide its own size and place its children, and how do positioned and non-positioned children differ?

level: juniorimportance: must knowfreq 70%

basics

~20 s

A Stack sizes itself to its largest non-positioned child, within its constraints, and aligns those children (default top-start). Positioned children don't affect its size; they are pinned by their insets afterwards, and later children paint on top.

open as a page

In Flutter, what is the difference between Expanded and Flexible inside a Row or Column, and what does FlexFit change?

level: middleimportance: must knowfreq 76%

basics

~20 s

Expanded is Flexible with FlexFit.tight: the child must fill its share of the leftover main-axis space. Flexible defaults to FlexFit.loose: the child may be smaller than its share, and the unused space stays free instead of going to siblings.

open as a page

In Flutter, when should a responsive widget read LayoutBuilder constraints instead of MediaQuery.sizeOf, and what does each one measure?

level: middleimportance: must knowfreq 65%

basics

~20 s

MediaQuery.sizeOf returns the app window's size in logical pixels; LayoutBuilder gives its builder the constraints the parent passes at that exact spot. Use sizeOf for app-level layout decisions and LayoutBuilder for a reusable widget that adapts to its own slot.

open as a page

In Flutter, why does SizedBox(width: 100, height: 100) returned as the root widget fill the whole screen, and how do you fix it?

level: middleimportance: must knowfreq 72%

basics

~20 s

The root receives tight constraints equal to the screen, and SizedBox clamps its own 100 by 100 request into them, so it has to be screen-sized. Putting Center or Align in between loosens the constraints so the request fits.

open as a page

Why are IntrinsicHeight and IntrinsicWidth considered expensive in Flutter, and when is using one still justified?

level: seniorimportance: must knowfreq 45%

basics

~20 s

They ask the whole subtree for its intrinsic size before real layout, a speculative pass that walks the subtree again and can become O(N²) in tree depth when nested. They are fine for a small, shallow subtree, such as one row of equal-height cards.

open as a page

In Flutter, what does FractionallySizedBox's widthFactor multiply, and why does it throw as a plain child of a Row?

level: juniorimportance: should knowfreq 30%

basics

~20 s

widthFactor multiplies the maximum incoming width and gives the child that exact width. As a plain Row child the maximum width is infinite, so the child gets an infinite tight width and layout throws 'BoxConstraints forces an infinite width'.

open as a page

In Flutter, how does AspectRatio choose its size from its constraints, and why can a 16:9 AspectRatio used as a GridView tile do nothing?

level: middleimportance: should knowfreq 42%

basics

~20 s

AspectRatio takes the largest width allowed, derives the height from the ratio, then adjusts to fit the constraints. Under tight constraints, such as a GridView tile, it must take the forced size and the ratio is ignored.

open as a page

In Flutter, how does FittedBox lay out and scale its child, and how do BoxFit.contain, cover and scaleDown differ?

level: middleimportance: should knowfreq 38%

basics

~20 s

FittedBox lays its child out with unbounded constraints, then scales and aligns it at paint time to fit its own size. contain (the default) fits the whole child, cover fills the box and may overflow, and scaleDown shrinks like contain but never enlarges.

open as a page

In Flutter, how do a Row's spacing parameter, Spacer and a SizedBox gap differ, and when should a Wrap replace the Row?

level: middleimportance: should knowfreq 38%

basics

~20 s

Row.spacing puts a fixed gap between adjacent children; a SizedBox is a fixed gap you place yourself; Spacer is an Expanded that absorbs leftover space. Use Wrap when children should flow onto new lines instead of overflowing.

open as a page

In Flutter, what do CrossAxisAlignment.stretch and CrossAxisAlignment.baseline do in a Row, and what does each require to work?

level: middleimportance: should knowfreq 42%

basics

~20 s

stretch gives every child tight cross-axis constraints equal to the Row's incoming max height, so it needs a bounded height. baseline lines up children's text baselines, and throws unless textBaseline is set; in a Column it acts like start.

open as a page

In Flutter's MediaQueryData, how do padding, viewPadding and viewInsets differ, and what happens to each when the software keyboard opens?

level: middleimportance: should knowfreq 40%

basics

~20 s

viewPadding is the area partly covered by system UI such as a notch or home indicator; viewInsets is the area fully covered, typically by the keyboard; padding is max(0, viewPadding - viewInsets). Opening the keyboard raises viewInsets.bottom and can drop padding.bottom to zero.

open as a page

In Flutter, what does OrientationBuilder actually measure, and why do the docs advise against switching whole layouts on orientation?

level: middleimportance: should knowfreq 38%

basics

~20 s

OrientationBuilder compares its parent's maxWidth with maxHeight: wider is landscape, anything else portrait. Orientation says nothing about how much room exists — a landscape phone can be narrower than a portrait tablet — so layouts should branch on width with breakpoints.

open as a page

In Flutter's BoxConstraints, what distinguishes tight, loose and unbounded constraints, and which common widgets hand out each?

level: middleimportance: should knowfreq 55%

basics

~20 s

Tight constraints have min equal to max, so one size is legal; loose ones have a zero minimum; unbounded ones have an infinite maximum. The root is tight, Center and Align loosen, and a Row or scroll view leaves its main axis unbounded.

open as a page

In Flutter, what do a Stack's fit and clipBehavior control, and why is an avatar badge with a negative offset cut off?

level: middleimportance: should knowfreq 45%

basics

~20 s

fit sets the constraints non-positioned children get: loosened (default), tightened to the biggest size, or passed through. clipBehavior defaults to Clip.hardEdge, so a Positioned badge with a negative inset that overflows the Stack is clipped; Clip.none lets it spill.

open as a page

In Flutter, what does IndexedStack do with the children it is not showing, and when is it the right tool for switching views?

level: middleimportance: should knowfreq 44%

basics

~20 s

IndexedStack keeps every child mounted and laid out but paints, hit-tests and exposes semantics only for the child at index, so hidden children keep their state. It sizes to the largest child and suits a few state-keeping views.

open as a page

In Flutter, how do Overlay with OverlayEntry and OverlayPortal differ when floating a photo-options popover above the current route?

level: middleimportance: should knowfreq 35%

basics

~20 s

An OverlayEntry is inserted into an Overlay by hand, built under the Overlay's context, and lives until removed. OverlayPortal builds its floating child inside its own subtree, so it shares that subtree's inherited widgets and cannot outlive it.

open as a page

A Flutter nutrition-label Row with an Expanded bar throws 'RenderFlex children have non-zero flex but incoming width constraints are unbounded'; why, and how do you fix it?

level: seniorimportance: should knowfreq 45%

basics

~20 s

The Row sits where its width is unbounded, such as a horizontal scroll view or a non-flexible slot of another Row, so an Expanded child has no finite leftover width to fill. Bound the Row's width, typically by making the Row itself flexible in its parent.

open as a page

How would you build one Flutter codebase so a note-taking app shows a list-detail split on tablets but a single pane with a separate detail view on phones?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Measure the window with MediaQuery.sizeOf or widthOf at the shell, branch on a width breakpoint such as 600, and render either a Row of list and detail or a single pane. Keep the selected note above the branch so resizing preserves it.

open as a page

A Flutter boarding-gate card's Row shows a yellow-and-black stripe reading 'RIGHT OVERFLOWED BY 42 PIXELS'; how do you diagnose it from the constraints, and what ships in release?

level: seniorimportance: should knowfreq 48%

basics

~20 s

The overflow report names the RenderFlex, its constraints and size: non-flexible children, measured under the Row's unbounded main axis, took 42 pixels more than the Row's width. Release builds draw no stripe and paint past the edge.

open as a page

A Flutter avatar Stack uses Clip.none so its camera button spills past the edge, but taps on the spilled part do nothing; why, and how do you fix it?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Hit testing starts at the root and each RenderBox rejects points outside its own size before asking its children, so taps outside the Stack never reach the button. Clip.none only affects painting. Enlarge the Stack so the button lies inside it.

open as a page

In Flutter, how do ConstrainedBox, UnconstrainedBox and LimitedBox differ in what they do to the constraints their child receives?

level: middleimportance: nice to knowfreq 30%

basics

~20 s

ConstrainedBox adds limits clamped inside the parent's range; UnconstrainedBox removes the parent's constraints so the child takes its natural size, overflowing with a debug warning if too big; LimitedBox caps an axis only when the incoming maximum is infinite.

open as a page

In Flutter, when would you use CustomMultiChildLayout or CustomSingleChildLayout, and what must a MultiChildLayoutDelegate's performLayout do?

level: seniorimportance: nice to knowfreq 15%

basics

~20 s

Use them when a child's constraints or position depend on measured sizes that Row, Column, Stack and Align cannot express. performLayout must call layoutChild exactly once for every child, identified by its LayoutId, and position each with positionChild.

open as a page

On a foldable Android device, how does a Flutter app locate a hinge or fold, and how do you keep content from straddling it?

level: seniorimportance: nice to knowfreq 15%

basics

~20 s

MediaQuery.displayFeaturesOf returns DisplayFeature objects with logical-pixel bounds, a type (fold, hinge, cutout) and a posture state; the list is populated only on Android. Split panes at a hinge's bounds, or wrap content in DisplayFeatureSubScreen to confine it to one side.

open as a page