## Learning Objectives

By the end of this chapter, you will be able to:

- Master Flutter's layout and constraint system and predict widget sizing behavior
- Use advanced layout widgets: Flex, Expanded, Flexible, Intrinsic, ConstrainedBox, SizedBox, FractionallySizedBox, LayoutBuilder, and CustomSingleChildLayout
- Build responsive UIs using MediaQuery, LayoutBuilder, and adaptive breakpoints
- Solve common layout problems: unbounded constraints, overflow, nested scrollables, and flexible spacing
- Apply practical patterns for reusable layout components

1

## Constraints-First Model Explained

Flutter's layout system is fundamentally different from traditional CSS-based layouts. Understanding the constraint model is crucial for building complex layouts.

### How Constraints Work

- Constraints flow down: Flutter's layout is driven by constraints flowing down from parent to child, and sizes flowing up from child to parent.
- Parent provides constraints: Parent gives min/max width/height; child picks a size within those bounds and reports it back.
- Common issues: Many layout surprises come from misunderstanding constraints (for example, a Column inside a ScrollView without constraints, or a ListView inside an unbounded-height parent).

### Key Mental Model

- Parent: "Here are your constraints."
- Child: "This is my chosen size within them."
- Parent: "I place the child at this position."

2

## Flex, Expanded, and Flexible

Understanding flex widgets is essential for creating flexible layouts that adapt to available space.

### Core Concepts

- Flex/Row/Column: Lay out children along one axis.
- Expanded: Forces the child to fill remaining space; it wraps a Flexible with tight fit.
- Flexible: Allows a child to take remaining space but can be loose, letting the child size itself.

### Pattern Examples

- Use Expanded to make a child fill available area in a Row or Column.
- Use Flexible when you want a child to take available space but still respect its intrinsic size.

### Code Sketch

    Row(
      children: [
        Icon(Icons.menu),
        Expanded(
          child: Text('Title fills remaining space'),
        ),
        Icon(Icons.search),
      ],
    )

Pitfall: Using multiple Expanded children divides remaining space according to their flex values.

3

## SizedBox, ConstrainedBox, and Intrinsic Widgets

These widgets provide fine-grained control over widget sizing and constraints.

### SizedBox

Fixed width/height or spacing helper.

### ConstrainedBox

Apply min/max constraints to a child.

### BoxConstraints

Construct flexible constraint combinations.

### IntrinsicWidth/IntrinsicHeight

Measure children to size to their intrinsic dimensions; expensive, avoid in lists or deeply nested trees.

### When to Use

- Use SizedBox for simple fixed gaps and spacers.
- Use ConstrainedBox to enforce minimum or maximum sizes (e.g., make a button at least 48 px tall).
- Use Intrinsic only when necessary for complex baseline alignment and accept performance cost.

### Example: Minimum Button Height

    ConstrainedBox(
      constraints: BoxConstraints(minHeight: 48),
      child: ElevatedButton(onPressed: () {}, child: Text('Tap')),
    )

4

## FractionallySizedBox and Align

These widgets enable percentage-based sizing and precise positioning.

### FractionallySizedBox

Sizes a child as a fraction of its parent's size. Useful for overlays and percentage-based sizing.

### Align

Positions a child within available space using alignment coordinates and can scale the child when widthFactor/heightFactor are provided.

### Example: Centered Box Half the Width

    FractionallySizedBox(
      widthFactor: 0.5,
      child: Container(color: Colors.blue, height: 100),
    )

5

## LayoutBuilder and MediaQuery for Responsiveness

Building responsive UIs requires understanding device metrics and available space.

### MediaQuery

Gives device metrics (screen size, orientation, textScaleFactor). Use for global breakpoints.

### LayoutBuilder

Provides the parent's constraints at build time and is ideal for adapting subtree layout based on available space.

### Responsive Pattern

- Use LayoutBuilder to switch between column layout (small widths) and row layout (large widths).
- Prefer LayoutBuilder for component-level responsiveness and MediaQuery for app-level metrics.

### Example Responsive Switch

    LayoutBuilder(builder: (context, constraints) {
      if (constraints.maxWidth < 600) {
        return Column(...); // mobile
      } else {
        return Row(...); // tablet/desktop
      }
    });

6

## Handling Unbounded Constraints and Scrollables

Understanding how scrollable widgets interact with constraints is crucial for avoiding layout errors.

### The Problem

- Scrollable widgets (ListView, SingleChildScrollView) provide unbounded constraints along their scroll axis.
- Common error: placing an unbounded widget inside a Column without constraining height causes layout exceptions.

### Solutions

- Wrap the scrollable in Expanded or SizedBox with fixed height.
- Use `shrinkWrap: true` for ListView when necessary but be mindful of performance costs.

### Example: Column with List

    Column(
      children: [
        Header(),
        Expanded(
          child: ListView.builder(itemBuilder: ...),
        ),
      ],
    )

7

## Nested Scrollables and Coordination

Coordinating multiple scrollable widgets requires careful design.

### Best Practices

- Avoid multiple scrollables inside each other unless using coordinated scroll controllers or NestedScrollView for app bars.
- For complex nested scrolling (collapsing headers + content lists), use NestedScrollView or CustomScrollView with Slivers.

Quick note: Slivers offer fine-grained control for performant, complex scrolling UIs.

8

## CustomSingleChildLayout and CustomMultiChildLayout

For highly customized layouts that built-in widgets cannot express.

### When to Use

Use CustomSingleChildLayout or CustomMultiChildLayout for precise control when built-in widgets cannot express a layout. These accept delegates that measure and position children explicitly.

Reserve these for: Complex, highly-customized components (floating panels, bespoke overlays) because they are more verbose and lower-level.

9

## Dealing with Overflow and Clipping

Overflow errors are common in Flutter. Understanding how to prevent and handle them is essential.

### Understanding Overflow

Overflow occurs when child size exceeds available constraints. Fixes: allow scrolling, reduce fixed sizes, use Flexible/Expanded, or wrap with SingleChildScrollView.

### Clipping

Use `ClipRect`, `ClipRRect`, or `OverflowBox` for controlled clipping when appropriate.

### Example: Prevent Overflow on Narrow Screens

Replace fixed-width text containers with Expanded or wrap long text with Flexible and `softWrap: true`.

10

## Adaptive and Accessible Layouts

Building layouts that work across devices and accessibility needs.

### Breakpoints and Scaling

- Choose breakpoints (e.g., 320, 600, 1024 px) that match your target devices.
- Scale touch targets and spacing for larger screens.
- Respect textScaleFactor from MediaQuery to support accessibility. Test with large font scaling.

### Adaptive Widget Hints

- Use `Adaptive` widgets or conditional UI (different icon sets, more columns on wide screens).
- Provide alternative navigation (Drawer vs BottomNavigationBar) depending on width.

11

## Reusable Layout Components

Creating reusable layout widgets improves code maintainability and consistency.

### Best Practices

- Create small, composable layout widgets: `Section`, `CardRow`, `TwoColumn`, `ResponsiveGrid`.
- Keep them parameterized (padding, spacing, breakpoint) so they are reusable across screens.

### Example Reusable Two-Column

    class TwoColumn extends StatelessWidget {
      final Widget left;
      final Widget right;
      const TwoColumn({required this.left, required this.right});

      @override
      Widget build(BuildContext context) {
        return LayoutBuilder(builder: (context, c) {
          if (c.maxWidth < 600) {
            return Column(children: [left, SizedBox(height: 12), right]);
          }
          return Row(children: [Expanded(child: left), SizedBox(width: 12), Expanded(child: right)]);
        });
      }
    }

12

## Debugging Layout Issues

Effective debugging techniques help you quickly identify and fix layout problems.

### Flutter's Visual Debugging Tools

- Use Flutter's visual debugging tools: Flutter Inspector, showLayoutBounds, and debugPaintSizeEnabled (dev only).
- Print constraints in a LayoutBuilder to see what the parent provides.
- Replace complex subtree with colored Containers to visualize sizes and alignment.
- Reproduce problematic devices/emulator sizes and orientations.

### Commands and Tips

- In debug mode enable "Toggle Debug Paint" in Flutter Inspector to see padding, alignments, and hit boxes.
- In code temporarily wrap widgets with `Container(color: Colors.red.withOpacity(0.2))` to visualize.

13

## Exercises

Practice what you've learned with these exercises:

### 1. Responsive landing section

Build a hero section that shows a single-column layout on narrow widths and a two-column layout on wide screens. The left column contains text and CTA, the right column contains an image that scales to 70% of available height.

### 2. Complex list layout

Create a list of cards where each card has an avatar, title, subtitle, and a trailing action. Ensure each card adapts: avatar and text stacked vertically on small screens and in a row on larger screens.

### 3. Nested scroll behavior

Build a screen with a SliverAppBar that collapses and a body containing a ListView. Use NestedScrollView or CustomScrollView to coordinate scrolling.

### 4. Constraint troubleshooting

Reproduce the Column-with-list overflow error, then fix it using at least two different strategies (Expanded, SizedBox with fixed height, or shrinkWrap) and document the trade-offs.

### 5. Reusable layout widget

Implement `ResponsiveGrid` that lays out children in 1, 2, or 3 columns depending on width breakpoints, accepts spacing parameters, and maintains consistent aspect ratio for children.

14

## Session Assignment

Complete Exercises 1–3. For each exercise include: source code, screenshots for narrow and wide layouts, and a short explanation (100–200 words) of why you chose the solution and any trade-offs observed. Highlight any use of LayoutBuilder or MediaQuery and explain how constraints influenced your layout decisions.