How do you create responsive layouts in Flutter?

Medium PriorityAsked in ~60% of Flutter interviews

3 min read

Widgets & UI

Theory — which API for which question

Question you're answeringUse
"How wide is the parent giving me?" (local)LayoutBuilder
"How wide is the device / window?" (global)MediaQuery.sizeOf(context)
"Share space proportionally inside a row/column"Expanded, Flexible
"Take a fraction of the parent"FractionallySizedBox
"Maintain a ratio"AspectRatio
"Wrap items onto new lines as space runs out"Wrap
"Grid where items have a target max width"GridView + SliverGridDelegateWithMaxCrossAxisExtent

Common breakpoints (Material): < 600 mobile, 600–840 tablet, > 840 desktop.


Code in action

// 1️⃣ Page-level: branch on device width
@override
Widget build(BuildContext context) {
  final w = MediaQuery.sizeOf(context).width;
  if (w >= 900) return const DesktopLayout();
  if (w >= 600) return const TabletLayout();
  return const MobileLayout();
}

// 2️⃣ Local-level: branch on parent constraints (better!)
LayoutBuilder(
  builder: (ctx, c) => c.maxWidth < 600
      ? const _List()
      : const _Grid(),
);

// 3️⃣ Flexible columns
Row(
  children: const [
    Expanded(flex: 2, child: ContentPane()),
    Expanded(flex: 1, child: Sidebar()),
  ],
);

// 4️⃣ Fluid grid — items decide how many columns fit
GridView.builder(
  gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
    maxCrossAxisExtent: 220,
    crossAxisSpacing: 12,
    mainAxisSpacing: 12,
    childAspectRatio: 1,
  ),
  itemCount: items.length,
  itemBuilder: (ctx, i) => ItemCard(items[i]),
);

// 5️⃣ Wrap — chips, tags, anything that should flow to next line
Wrap(spacing: 8, runSpacing: 8, children: chips);

// 6️⃣ Aspect-ratio preserving — videos, cover art
AspectRatio(aspectRatio: 16 / 9, child: VideoPlayer(controller));

LayoutBuilder vs MediaQuery — which one?

Use LayoutBuilder when…Use MediaQuery when…
The widget could be anywhere in the tree (sidebar, dialog, sheet)You're branching at the page level on device size
You care about available space, not screen sizeYou need orientation, padding, brightness, text scale
You want to be embeddable in a smaller containerYou want a single breakpoint for the whole app

A common bug: using MediaQuery.sizeOf(context) inside a card that's actually 300px wide — you'd render the desktop layout in a tiny corner.


Common mistakes to avoid

// ❌ Hard-coded pixel widths
SizedBox(width: 320, child: ...);                // breaks on small screens
// ✅ Use Expanded/FractionallySizedBox or branch on constraints

// ❌ MediaQuery.of(context) when you only need size
final mq = MediaQuery.of(context);               // subscribes to ALL metrics
// ✅ MediaQuery.sizeOf(context) — rebuilds only when size changes

// ❌ Branching on device size inside a small embedded widget
LayoutBuilder(builder: (ctx, c) {                // good
  return MediaQuery.of(ctx).size.width > 600 ... // wrong inside a side panel
});

// ❌ Forgetting text scale
// Users can set huge font sizes — test with MediaQuery.textScalerOf

// ❌ Trusting orientation alone
// A foldable in landscape vs phone in landscape are different widths — branch on size, not orientation

Interview follow-ups

  1. LayoutBuilder vs MediaQuery — when do you use each? LayoutBuilder answers "how much space did my parent give me?" — perfect for self-contained, embeddable widgets. MediaQuery answers "what's the device like?" — best for app-wide breakpoints and reading insets/padding/orientation.

  2. Why does MediaQuery.sizeOf(context) exist alongside MediaQuery.of(context)? The of version subscribes to every MediaQueryData field — so a keyboard appearing causes a rebuild even if you only care about screen size. .sizeOf, .paddingOf, .textScalerOf etc. let you subscribe to one slice and avoid spurious rebuilds.

  3. How do you handle text scaling for accessibility? Don't fight it — use Text (it scales by default), avoid hard-coded heights for text containers, test at large text scales. For controlled layouts, read MediaQuery.textScalerOf(context) and adjust.

  4. What's the cleanest way to build a 1-column / 2-column / 3-column responsive grid? Use GridView.builder with SliverGridDelegateWithMaxCrossAxisExtent — set the max item width, and Flutter computes the column count for you. Adapts smoothly across phone, tablet, and desktop.


How helpful was this content?

Please sign in to rate this article.