## Learning Objectives

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

- Understand Flutter's widget-centric architecture and widget tree concept
- Differentiate StatelessWidget and StatefulWidget and choose appropriately
- Compose UI using common layout widgets (Container, Row, Column, Stack)
- Apply alignment, padding, margin, and constraints principles
- Know basic widget lifecycle for stateful widgets and common performance tips
- Build a small multi-widget screen and test it in an emulator

1

## Flutter's Widget-First Architecture

Flutter's architecture is fundamentally different from traditional UI frameworks. Understanding this concept is crucial for effective Flutter development.

### Core Principles

- Everything is a widget: Layout, styling, and even gesture handling are widgets.
- Immutable descriptions: Widgets are lightweight immutable descriptions of part of the UI; the framework builds and updates RenderObjects under the hood.
- Composition over mutation: UI is built by composing widgets into a tree. Updating UI means creating new widget instances — Flutter diffs the tree and efficiently updates the rendered output.

Key idea: Think in terms of composition, not mutation of UI elements.

2

## Widget Tree and Composition

Understanding the widget tree structure helps you organize your Flutter applications effectively.

### Widget Tree Structure

- Root widget: Typically `MaterialApp` (Material design) or `CupertinoApp` (iOS style).
- Scaffold: Each screen commonly uses `Scaffold` (app bar, body, floating action button).
- Nesting: Widgets nest: parent widgets provide layout and behavior to children. Keep widget trees readable by extracting subtrees into their own widgets.

Practical rule: One file per major widget or screen for clarity; small helper widgets inline when simple.

3

## StatelessWidget vs StatefulWidget

Choosing the right widget type is fundamental to building efficient Flutter applications.

### StatelessWidget

Use when UI depends only on constructor parameters and never changes during the widget's lifetime. They are cheap and rebuild frequently without preserving state.

### StatefulWidget

Use when UI depends on mutable state that changes over time (user input, timers, network results). A StatefulWidget has a State object where mutable fields live and `setState()` triggers rebuilds.

### Example Pattern (Stateless)

    class GreetingCard extends StatelessWidget {
      final String name;
      const GreetingCard({Key? key, required this.name}) : super(key: key);

      @override
      Widget build(BuildContext context) {
        return Text('Hello, $name');
      }
    }

### Example Pattern (Stateful)

    class CounterPage extends StatefulWidget {
      const CounterPage({Key? key}) : super(key: key);

      @override
      _CounterPageState createState() => _CounterPageState();
    }

    class _CounterPageState extends State {
      int _count = 0;

      void _increment() => setState(() => _count++);

      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            Text('Count: $_count'),
            ElevatedButton(onPressed: _increment, child: Text('Increment')),
          ],
        );
      }
    }

### Decision Checklist

- If you need to call `setState()` or hold references to controllers (TextEditingController, AnimationController), use StatefulWidget.
- Prefer moving state up (lifting state) to avoid duplicating state across widgets.

4

## Common Layout Widgets and Their Uses

Flutter provides a rich set of layout widgets. Understanding when to use each is key to building effective UIs.

### Container

Single-child box with padding, margin (via Padding/Align), background, border, size constraints. Use sparingly; prefer dedicated widgets (Padding, SizedBox) for clarity.

### Row and Column

Linear layouts horizontal and vertical. Use `mainAxisAlignment`, `crossAxisAlignment`, and `mainAxisSize`.

### Expanded/Flexible

Make children fill available space in Row/Column. `Expanded` forces fill; `Flexible` gives flexibility.

### SizedBox

Fixed spacing or empty space.

### Padding

Adds internal spacing.

### Align/Center

Position a child within available space.

### Stack

Overlap children; use `Positioned` for explicit placement.

### ListView

Scrollable linear list (use builder for large lists).

### GridView

Grid layout for items.

Column pitfalls: Avoid unbounded height errors by wrapping scrollable content in `Expanded` or using `SingleChildScrollView`.

### Example Snippet: Profile Card Layout

    Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            CircleAvatar(radius: 30, child: Icon(Icons.person)),
            SizedBox(width: 12),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text('Adu Amankwah', style: Theme.of(context).textTheme.subtitle1),
                  Text('Flutter student', style: Theme.of(context).textTheme.bodyText2),
                ],
              ),
            ),
          ],
        ),
      ),
    )

5

## Alignment, Padding, Margin, and Constraints

Understanding spacing and constraints is essential for creating well-laid-out Flutter applications.

### Spacing Concepts

- Padding: Space inside a widget (use `Padding` or `Container.padding`).
- Margin: Outside spacing — achieved with parent widgets like `Padding` or `SizedBox` around the child.
- Alignment: Positions children inside a parent (e.g., `Align(alignment: Alignment.centerRight)`).

### Constraints Flow

Constraints flow down: parents tell children their constraints (min/max width/height); children choose size and tell parents their size. Understand constraints to avoid layout exceptions (e.g., "RenderBox was not laid out" or unbounded height inside Column).

Practical tip: When a vertical Column contains a scrollable ListView, wrap the ListView in Expanded or set `shrinkWrap: true` and avoid nesting scrollables unnecessarily.

6

## Text, Images, and Assets

- Text styling via `TextStyle` and themes. Prefer using `Theme.of(context)` to keep app consistent.
- Images: `Image.asset` for packaged assets, `Image.network` for remote images, `FadeInImage` for smooth placeholders. Add images to `pubspec.yaml` under `assets:`.
- Iconography: `Icon` widget with `Icons.*` or custom icon fonts.

### Assets Example (pubspec.yaml excerpt)

    flutter:
      assets:
        - assets/images/profile.png

7

## Widget Lifecycle Basics (StatefulWidget)

### Important Lifecycle Callbacks in State

- `initState()` — called once when the state object is first created; initialize controllers, start listeners.
- `didChangeDependencies()` — called after initState and when dependencies change (e.g., InheritedWidget updates).
- `build()` — called often; must be pure and fast.
- `didUpdateWidget(Widget oldWidget)` — when parent widget rebuilds with new configuration.
- `dispose()` — clean up controllers, listeners, timers to avoid leaks.

Rule: Heavy initialization should be in `initState()`, and always `dispose()` controllers.

### Example

    @override
    void initState() {
      super.initState();
      _controller = TextEditingController();
    }

    @override
    void dispose() {
      _controller.dispose();
      super.dispose();
    }

8

## Performance Tips and Best Practices

- Minimize work inside `build()`; avoid heavy computations — move them to model or compute once and cache.
- Use const constructors (`const Text('Hello')`) where possible to reduce rebuild costs.
- Extract subtrees into separate widgets so only those widgets rebuild when their inputs change.
- Use `ListView.builder` for long or infinite lists to build items lazily.
- Avoid setState on large widgets; scope state to the smallest subtree necessary.

9

## Interactivity: Gestures and Buttons

- Buttons: `ElevatedButton`, `TextButton`, `IconButton`, `OutlinedButton`. Use `onPressed` to handle taps.
- Gesture detectors: `GestureDetector` for low-level events (tap, long press, drag) when a ready widget is not available.
- Forms: `Form` + `TextFormField` + `FormState` for validated inputs.

### Example Button

    ElevatedButton(
      onPressed: () { /* handle */ },
      child: Text('Save'),
    )

10

## Accessibility and Responsiveness (Short)

- Use semantic labels (`Semantics`) for non-text UI elements and alt information for images.
- Make touch targets large enough (44–48 px recommended).
- Use `LayoutBuilder` or MediaQuery for responsive layouts; test on multiple device sizes and orientations.

11

## Small Guided Build: Simple Profile Screen

### Goal

Compose a profile screen showing avatar, name, bio, and a follow button with counter.

### Structure

- Scaffold → AppBar
- Body → Column with top Card (avatar + name + bio) and follow button that increments state

### Key Points to Implement

- Use StatefulWidget to hold follow count
- Extract profile card into a StatelessWidget that accepts parameters
- Use padding, Row, CircleAvatar, Expanded, and ElevatedButton

12

## Exercises

### 1. Build a responsive profile screen

Avatar (local asset), name, role, and a short bio. Follow button increments a counter and updates label to "Following (n)".

### 2. Layout practice

Create a grid of colored tiles using `GridView.count` with 3 columns and spacing.

### 3. ListView builder

Create a list of 100 generated names and display them with separators; tapping an item shows a SnackBar with the name.

### 4. Form practice

Build a simple login form with `TextFormField` for email and password and basic validation (non-empty, email contains `@`).

13

## Session Assignment

Implement exercise 1 (profile screen) and exercise 4 (login form). Ensure TextEditingControllers are disposed correctly. Add comments describing why you chose Stateless vs Stateful for each widget. Submit source code and short screenshots or run logs.