skip to content

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%

answer

  1. window versus the parent's slot
  2. Size versus BoxConstraints
  3. builder runs during layout
  4. sizeOf rebuilds only when size changes
  5. infinite maxWidth inside a Row

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.

solid answer

~50 s

`MediaQuery.sizeOf(context)` reads the `Size` of the view the app is drawn in — the window, which may be a split-screen pane rather than the whole screen — and makes the caller rebuild only when that size changes. `LayoutBuilder` is different in kind: the framework calls its `builder` during **layout** with the `BoxConstraints` its parent hands down, so it knows how much room *this widget* has, not the app. I reach for `sizeOf` (or `MediaQuery.widthOf` since 3.35) when choosing the overall shell — a single pane versus a split. I use `LayoutBuilder` inside a component, such as a note card that switches from a stacked to a side-by-side layout when its column is wide enough. One trap: a `LayoutBuilder` placed where the parent gives unbounded width, such as a plain child of a `Row`, sees `maxWidth == double.infinity`, so width breakpoints stop working.

code

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

class NotePreview extends StatelessWidget {
  const NotePreview({super.key, required this.title, required this.body});

  final String title;
  final String body;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        final bool wide = constraints.hasBoundedWidth && constraints.maxWidth >= 400;
        final Widget text = Text(body, maxLines: wide ? 6 : 2, overflow: TextOverflow.ellipsis);
        if (wide) {
          return Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[SizedBox(width: 160, child: Text(title)), Expanded(child: text)],
          );
        }
        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[Text(title), text],
        );
      },
    );
  }
}

go deeper

for a junior

Know that MediaQuery.sizeOf gives the window size and LayoutBuilder gives the parent's constraints, and be able to branch on a width with either.

for a middle

Explain that LayoutBuilder's builder runs during layout with BoxConstraints, why sizeOf is cheaper than MediaQuery.of, and what happens under unbounded constraints.

for a senior

Show where each belongs in a real app: sizeOf for the shell, LayoutBuilder for components, and how you test both at several window sizes including split-screen.

for a principal

Argue for measuring available space over device detection as a team rule, and weigh one adaptive component set against maintaining separate phone and tablet screens.

## Two different questions A **responsive** layout changes its arrangement to fit the space it has. Flutter offers two ways to learn how much space that is, and they answer different questions: | | `MediaQuery.sizeOf(context)` | `LayoutBuilder` | |---|---|---| | What it reports | the `Size` of the app's view (window) | the `BoxConstraints` from the parent at this spot | | Type | `Size` (one width, one height) | min and max width and height | | When it is read | during **build** | during **layout**, when the builder is called | | Rebuild trigger | the window size changes | the incoming constraints change | | Best for | app-shell decisions | self-contained, reusable widgets | Both work in **logical pixels** (density-independent units), so 600 means roughly the same physical width on any screen. ## MediaQuery.sizeOf and its siblings `MediaQuery` sits near the top of every app (created by `WidgetsApp`, and so by `MaterialApp` and `CupertinoApp`) and carries a `MediaQueryData` object: size, padding, insets, orientation and more. Older code read `MediaQuery.of(context).size`. That call makes the widget depend on the **whole** `MediaQueryData`, so it rebuilds when the keyboard opens, when padding changes or when any other field moves. `MediaQuery.sizeOf(context)` depends only on the size, so it rebuilds only when the size changes. Flutter 3.35 added `MediaQuery.widthOf` and `MediaQuery.heightOf`, which narrow the dependency to one dimension. Key facts: - the size is of the **window**, not the physical display — in split-screen, freeform or picture-in-picture mode it is the app's share; - a nested `MediaQuery` can override it for a subtree; - it knows nothing about where the calling widget sits, so a sidebar and a full-width body read the same value. ## LayoutBuilder and the layout phase Flutter lays out with one rule: **constraints go down, sizes go up, the parent sets the position**. `LayoutBuilder` hooks into that pass. Instead of building its child during the build phase, it defers the call to its `builder` until layout, when its own constraints are known, and passes them in. The builder can then return a different subtree depending on `constraints.maxWidth`. The `LayoutBuilder` ends up the same size as the child it builds. Because it measures the **slot**, the same widget behaves correctly wherever it is placed: full-width on a phone, inside a 320-pixel column on a tablet, or in a resizable desktop pane. ## Choosing between them 1. Deciding the app's **overall structure** (one pane or two, bottom or side navigation)? Read the window with `MediaQuery.sizeOf` or `widthOf`, because the decision is about the whole window. 2. Building a **component** that should adapt wherever it is dropped? Wrap it in a `LayoutBuilder`. 3. Need the **range** rather than a single number, for example to know whether height is bounded? Only `LayoutBuilder` gives min and max values. ## Pitfalls interviewers probe - **Unbounded constraints.** A non-flex child of a `Row` receives unlimited width; a child of a vertical scroll view receives unlimited height. A `LayoutBuilder` there sees `double.infinity`, and `maxWidth >= 600` is always true. Check `constraints.hasBoundedWidth` or give the child a bounded slot. - **Checking the device type.** Deciding "tablet" from the platform or a model name ignores split-screen and resizable windows. Measure the space instead. - **Using `MediaQuery.of` for size.** It still works, but it rebuilds on unrelated changes such as the keyboard. - **Assuming the builder runs at build time.** It runs during layout, so it cannot be used by a parent that asks for intrinsic dimensions. In short: `sizeOf` answers "how big is the window?"; `LayoutBuilder` answers "how much room did my parent give me?"

  • Why can a LayoutBuilder placed directly inside a Row break width breakpoints?
    `Row` lays out its non-flex children with no maximum width, so the builder sees `maxWidth == double.infinity` and every `>=` breakpoint is true. Wrap the child in `Expanded` or `Flexible`, or give it a `SizedBox`, so it receives a bounded slot, and check `constraints.hasBoundedWidth` before comparing.
  • Why prefer MediaQuery.sizeOf over MediaQuery.of(context).size?
    `MediaQuery.of` registers a dependency on the whole `MediaQueryData`, so the widget rebuilds when the keyboard changes `viewInsets`, when padding changes, and so on. `sizeOf` depends only on the size aspect, so it rebuilds only when the window is resized. `widthOf` and `heightOf`, added in Flutter 3.35, narrow it to one dimension.
  • Does MediaQuery.sizeOf return the physical screen size?
    No. It returns the logical size of the view the app is drawn in. In split-screen, freeform or picture-in-picture that is the app's window, not the display. The physical display is available through the `Display` object reached from `View.of(context).display`, which reports physical pixels and is rarely the right input for layout.

MediaQuery.sizeOf tells you the size of the whole house; LayoutBuilder tells you the size of the room your furniture is going into.

saying these in an interview costs you the question

  • MediaQuery.sizeOf returns the size of the widget that calls it.
  • LayoutBuilder returns a Size, exactly like MediaQuery.sizeOf.
  • The LayoutBuilder builder runs during the build phase, like Builder.
  • MediaQuery.of(context).size rebuilds no more often than MediaQuery.sizeOf.
  • Checking whether the device is a tablet is the right way to pick a layout.