BXUP Track progress & test yourself — free
Frontend & Mobile · Playbook · Foundation · ~5 min read
FRONTEND & MOBILE · PLAYBOOK · FOUNDATION

Preview-Driven UI Iteration: Generate the Full State Matrix

Most mobile UI bugs ship because the developer only ever rendered the happy path. Generate Compose and SwiftUI previews for every state — loading, error, empty, RTL, dynamic type, dark mode — so verifying a screen means clicking through a preview gallery, not building the app six times.

Tier: Foundation · Workflow area: Mobile engineering & release

This playbook makes the state matrix a generated artifact: AI enumerates and writes the previews, you render and judge them, and the gallery becomes the screen's living spec.

When to use

  • Any new Compose or SwiftUI screen or nontrivial component — before the first PR.
  • Retrofitting preview coverage onto an existing screen you are about to modify, so regressions become visible.
  • Design review prep: a rendered matrix answers "what does error look like in dark mode with large text" instantly.

Skip it for pure-logic changes with no visual surface, and for throwaway spikes that will not be reviewed.

Prerequisites

  • Working previews: Compose @Preview rendering in Android Studio, or SwiftUI #Preview in Xcode's canvas. If previews are broken, fix that first — everything here depends on cheap rendering.
  • Components that take state as parameters (or a ViewModel that can be constructed with fake state). Screens that fetch inside the composable/view need a small refactor to be previewable; that refactor is worth it and AI can do it.
  • An AI assistant with the screen's source in context: Gemini in Android Studio (including its generate-preview assist), Xcode's assistant, or any coding agent.
  • Sample fixture data (a fake user, a long product list, an error object) in a shared PreviewData/fixtures file.

The workflow

  1. Have AI enumerate the matrix before writing any preview. Enumeration is where humans under-count, so make it explicit:

    Here is OrderHistoryScreen and its UiState. List every visually
    distinct state a user could see. Cover: loading (first load and
    pagination), error (retryable and fatal), empty, partial data,
    longest realistic content, single item, and offline. Then cross with
    presentation axes: dark mode, RTL, dynamic type at the largest
    accessibility size, and smallest supported screen width.
    Output a table: state x axis, marking which combinations matter.
    

    Prune the table — you want the 10–20 combinations that can actually differ, not the full cross-product.

  2. Generate the previews from the table. For Compose:

    Write @Preview functions for each row of the approved table. Use
    PreviewParameterProvider for the UiState variants. Use
    @Preview(uiMode = UI_MODE_NIGHT_YES) for dark, locale = "ar" for RTL,
    fontScale = 2f for large text, and device/widthDp for the small-width
    case. Pull fixture data from PreviewData. One file:
    OrderHistoryScreenPreviews.kt.
    

    For SwiftUI, the same request maps to multiple #Preview blocks with .preferredColorScheme(.dark), .environment(\.layoutDirection, .rightToLeft), .environment(\.dynamicTypeSize, .accessibility3) and fixture-injected view models. In Android Studio you can also use the Gemini preview-generation assist on a composable and then ask for the missing variants — the assist gives you one preview; the matrix is what you add.

  3. Render the gallery and actually look. Open the preview grid and inspect every cell for the classic failures: truncated text at large type, layouts that do not mirror in RTL, hardcoded white backgrounds in dark mode, empty states that render as a blank screen, spinners with no minimum height causing layout jumps. Fix in the component, not the preview.

  4. Ask AI to critique the rendered states. Screenshot the grid (or individual odd cells) and feed it back:

    Here is the preview grid for OrderHistoryScreen. Flag: text that
    looks truncated or clipped, contrast problems in dark mode, spacing
    that collapses at fontScale 2, and any state where a user would not
    know what to do next. Rank by severity.
    

    Multimodal critique catches things you scroll past; you still adjudicate every flag.

  5. Commit the previews as the screen's spec and wire them forward. The preview file ships with the screen and is updated in the same PR as any state change. If you have screenshot testing (Paparazzi, Roborazzi, swift-snapshot-testing), point it at these same previews so the matrix becomes a CI regression net rather than a manual gallery.

Key Takeaway:

The unit of review for a screen is the rendered state matrix, not the code diff. AI makes the matrix cheap to enumerate and generate; your job is the two minutes of actually looking at every cell.

Tool variants

  • Gemini in Android Studio: the built-in preview-generation assist plus chat for the matrix; Layout Inspector to chase anything a preview cannot reproduce.
  • Xcode assistant: generate #Preview variants directly in-file; the canvas's device and color-scheme toggles complement the coded variants.
  • Terminal agent (Claude Code): best for backfilling previews across a whole module in one pass — give it the matrix prompt, the fixtures file and one exemplar preview file as the pattern.

Verification

  • Every state in the approved table has a preview that renders without error, and you visually inspected each one.
  • Dark mode, RTL, and the largest accessibility type size render acceptably — no clipped labels, unmirrored chevrons, or invisible text.
  • Empty and error states include a user action (retry, CTA), not just a message.
  • Fixture data is realistic — longest names, 0 items, 500 items — not "Test User" everywhere.
  • If screenshot tests exist, the new previews are enrolled and the baseline is committed.

Pitfalls

  • Generating the matrix but never rendering it. Preview code that is committed unrendered is worse than nothing — it implies verification that did not happen.
  • Preview-only fixes. Adjusting the preview (shorter fixture strings) instead of the component hides the bug the matrix just found.
  • Unpreviewable screens. Composables/views that fetch or read singletons inside themselves cannot be previewed honestly; refactor state to parameters first, and let AI do that refactor.
  • Full cross-product explosion. 8 states × 4 axes = 32 previews nobody maintains; the pruning pass in step 1 is mandatory.
  • Fixture drift. Fixtures that no longer match the real API shape make every preview a lie; regenerate fixtures when the DTO changes.

Restricted-environment variant

Preview generation works entirely on code you paste, so a local model (Ollama/LM Studio) handles steps 1–2 acceptably — enumeration and preview boilerplate are not frontier-model problems. The multimodal critique in step 4 needs a vision-capable model; where screenshots cannot leave the machine, replace it with a manual checklist pass (truncation, contrast, RTL mirroring, tap-target size) over the same grid.

Note

Preview screenshots of an unreleased product are still confidential product material — treat them with the same care as source when choosing which model sees them.

Success criteria

  • New screens merge with their full pruned matrix previewed, and "what does X state look like" is answered by opening one file.
  • Dark-mode, RTL and large-type regressions are caught at preview time — zero such bugs reaching QA for covered screens.
  • Backfilled modules show the same: modifying a screen without updating its previews fails review by convention.
  • Design reviews run off the rendered matrix, cutting a build-and-navigate demo cycle out of every iteration.
This is the free reading view. Open BXUP to track your progress, run the hands-on labs, and prove it with original, exam-pattern assessments.
© Anvi Innovate · BXUP — Be Exponentially Upskilled · BXUP is an independent learning platform, not affiliated with or endorsed by AWS, Microsoft, Google, NVIDIA, IBM, Salesforce, Databricks, Oracle or Anthropic. All trademarks belong to their respective owners. · bxup.in