## Learning Objectives

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

- Display collections with ListView, GridView, and slivers
- Build efficient, scrollable lists using builders and pagination
- Render heterogeneous lists and separators; implement swipe-to-dismiss and item reordering
- Bind collections to state and update UI reactively with minimal rebuilds
- Handle empty, loading, and error states for list-driven UIs

1

## When to Use Which Widget

Choosing the right widget for displaying collections is crucial for performance and user experience.

### ListView

Vertical or horizontal linear lists; use when items are arranged one after another.

### GridView

Multi-column layouts for media, products, or tiles.

### CustomScrollView + Slivers

Advanced, high-performance scroll effects and mixed content (collapsing app bars, varied item types).

Key point: Use builder constructors (ListView.builder, GridView.builder, SliverList/SliverGrid with delegates) for large or infinite lists to build items lazily.

2

## ListView Patterns

ListView provides several constructors for different use cases.

### ListView Constructors

- `ListView(children: [...])` — small, fixed-size lists.
- `ListView.builder(itemCount: n, itemBuilder: ...)` — efficient for large lists.
- `ListView.separated` — insert separators between items easily.

### Example Patterns (Conceptual)

Simple builder:

    ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        final item = items[index];
        return ListTile(title: Text(item.title));
      },
    )

Separated:

    ListView.separated(
      itemCount: items.length,
      itemBuilder: ...,
      separatorBuilder: (context, index) => Divider(),
    )

### Key Points

- Use const where possible for static children.
- Provide keys (ValueKey or ObjectKey) for stateful list items that may reorder to preserve state.

3

## GridView and Responsive Grids

GridView provides flexible layouts for displaying items in a grid format.

### GridView Options

- `GridView.count` — quick fixed column grids.
- `GridView.builder` with `SliverGridDelegateWithFixedCrossAxisCount` or `WithMaxCrossAxisExtent` — flexible, performant grids.

### Responsive Grid Example

Use maxCrossAxisExtent to let items adapt to available width:

    GridView.builder(
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 200,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        childAspectRatio: 3/4,
      ),
      itemBuilder: ...
    )

4

## Keys and Preserving State

Keys are essential for maintaining state when lists change.

### Using Keys

- Use keys to preserve identity when reordering or updating lists.
- `ValueKey(item.id)` is common when items have stable IDs.
- Without keys, Flutter may rebuild and lose state (e.g., text field cursor position) when items move.

### Example

    ListTile(key: ValueKey(item.id), title: Text(item.name));

5

## Heterogeneous Lists and Item Types

Lists often contain different types of items that require different widgets.

### Handling Different Item Types

- When lists contain different item widgets (headers, cards, ads), switch on item type in itemBuilder.
- For Sliver-based lists, use SliverList with child delegates that produce different widgets.

### Pattern

    if (item is Header) return HeaderWidget(...);
    if (item is Product) return ProductTile(...);

6

## Swipe-to-Dismiss and Dismissible

Dismissible widgets enable intuitive deletion gestures.

### Using Dismissible

Use `Dismissible` to allow swipe-to-delete with animation and background widgets. Provide a unique key and handle confirm/undo flows.

### Example

    Dismissible(
      key: ValueKey(item.id),
      background: Container(color: Colors.red, child: Icon(Icons.delete)),
      onDismissed: (direction) { cart.remove(item); },
      child: ListTile(title: Text(item.name)),
    )

UX note: Support undo via SnackBar with action that restores item; avoid immediate permanent deletion without confirmation in critical flows.

7

## ReorderableListView

ReorderableListView enables drag-and-drop reordering of list items.

### Using ReorderableListView

Use `ReorderableListView` for drag-and-drop reordering. Maintain underlying list order and update state on `onReorder(oldIndex, newIndex)`.

Important: Provide keys on children and ensure stable ids. Update models and persist new order if necessary.

8

## Infinite Lists, Pagination, and Pull-to-Refresh

Pagination and refresh patterns are essential for handling large datasets.

### Pagination Strategies

- Offset/limit (load next page at end): Common and simple.
- Cursor-based pagination: Robust for changing datasets.

### Implementation

- Detect scroll position with `ScrollController` and trigger loading when approaching the end.
- Use `RefreshIndicator` to enable pull-to-refresh for manual reload.

### Example Scroll Detection Pattern

    _scrollController.addListener(() {
      if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 200) {
        // load next page
      }
    });

### Best Practices

- Debounce or guard concurrent page loads with a `isLoadingMore` flag.
- Show loading footer or skeleton while loading.
- Handle empty results and end-of-list states to avoid repeated calls.

9

## Slivers for Advanced Scrolling

Slivers provide powerful scrolling capabilities for complex UIs.

### CustomScrollView with Slivers

`CustomScrollView` with `SliverAppBar`, `SliverList`, `SliverGrid`, `SliverToBoxAdapter` lets you mix different scrollable sections and create collapsing headers, sticky sections, and performant large lists. Use `SliverChildBuilderDelegate` for lazy child creation and provide keys as needed.

### Use Case

Collapsing toolbar (SliverAppBar) + product grid below, with performant scrolling and pinned headers.

10

## Performance and Memory Tips

Optimizing list performance is crucial for smooth user experience.

### Performance Best Practices

- Use builder variants to avoid building off-screen widgets.
- For heavy list items, precompute or cache expensive subparts outside build (e.g., image decoding).
- Use const and small leaf widgets to minimize rebuild cost.
- Recycle image widgets with `cached_network_image` or similar to avoid re-downloading.

11

## Binding Collections to State

Connecting lists to state management ensures reactive updates.

### State Binding

- Keep source-of-truth list in a provider/state notifier. UI subscribes and rebuilds only necessary parts (use selectors to avoid full-list rebuilds if only a badge count changes).
- When modifying lists (add/remove/reorder), update the model then call notifyListeners or setState accordingly.

### Example (Provider)

    final items = context.watch().items;
    ListView.builder(... itemCount: items.length ...)

### Optimization

Use `ListView.builder` and item-level `ChangeNotifier` or `ValueListenable` for per-item state to avoid rebuilding the entire list on small changes.

12

## Empty, Loading, and Error States

Providing feedback for different states improves user experience.

### User Feedback States

- Loading: Centered spinner or skeleton placeholders.
- Empty: Friendly illustration and CTA.
- Error: Retry action and clear error copy.

For paginated lists, show loading footer and preserve previously loaded items while loading more.

13

## Accessibility and Touch Targets

Making lists accessible ensures all users can interact with them effectively.

### Accessibility Best Practices

- Ensure tappable list items meet minimum size and have proper semantics for screen readers.
- Provide meaningful labels for each item and use `ListTile` semantics where appropriate.

14

## Exercises

Practice what you've learned with these exercises:

### 1. Product list with grid and pagination

Build a grid of product cards that loads initial page, loads next page on scroll, and shows a loading footer. Include a pull-to-refresh to reload the first page.

### 2. Reorderable todo list with persistence

Create a ReorderableListView for todos. Persist order locally (SharedPreferences or local JSON file) and reload on app start.

### 3. Heterogeneous feed with Slivers

Build a CustomScrollView containing: a SliverAppBar, a SliverList of posts, a SliverToBoxAdapter ad banner, and a SliverGrid of recommendations.

### 4. Swipe-to-delete with undo

Implement a dismissible shopping list where swiping removes item and shows SnackBar with Undo action to restore it.

15

## Session Assignment

Complete Exercises 1 and 4. Provide code, screenshots for loading/empty/error states, and a short README describing your pagination approach and how you avoided duplicate loads.