Native Android Design
Use this skill for visual design decisions and design-focused audits in native Android apps. Prefer it when the user needs Material 3 aligned screen structure, current Android-native visual defaults, or a screenshot-to-fix loop after a fresh verified build/install/launch. If the request is really about greenfield scaffolding, Gradle build loops, module selection, or broader Android implementation workflow, route to software-mobile and return here once the question becomes visual structure or design quality.
Quick Reference
| Design concern | Default | Notes |
|---|---|---|
| Type | MaterialTheme.typography |
Display → Headline → Title → Body → Label scale |
| Color | MaterialTheme.colorScheme |
primary, secondary, tertiary, surface, error, and on* variants |
| Shape | MaterialTheme.shapes |
ExtraSmall→ExtraLarge; RoundedCornerShape |
| Dynamic color | dynamicDarkColorScheme / dynamicLightColorScheme |
Android 12+; static seed palette on older APIs |
| Bottom nav | NavigationBar 3–5 destinations |
NavigationRail on medium, NavigationDrawer on expanded, or NavigationSuiteScaffold for auto |
| Top bar | TopAppBar / MediumTopAppBar / LargeTopAppBar / CenterAlignedTopAppBar |
Choose by headline presence; collapsing variants for rich headers |
| Cards | ElevatedCard hero, Card primary, OutlinedCard secondary |
tonalElevation 3 + shadow for hero |
| Custom data viz | Canvas |
Radar charts, score rings, gradient bars, gauges — standard components insufficient |
| Adaptive layouts | ListDetailPaneScaffold, SupportingPaneScaffold, NavigationSuiteScaffold |
Feed grids for homogeneous content |
| Detail views | ModalBottomSheet |
Never expand deep detail inline in scroll content |
| Motion | Container transforms, AnimatedVisibility, animateContentSize, spring() |
M3 Expressive defaults |
| Edge-to-edge | enableEdgeToEdge() + windowInsetsPadding |
Mandatory, non-optional for targetSdk 36+ (windowOptOutEdgeToEdgeEnforcement removed) |
| Predictive back | PredictiveBackHandler (Compose) / OnBackInvokedCallback |
Default system animation on Android 16+ when targeting API 36+; onBackPressed()/KEYCODE_BACK no longer dispatched at that target |
| Press feedback | InteractionSource + animateFloatAsState(0.94f), 100ms spring |
Modifier.clickable without Indication = no tactile response |
| Chip groups | FlowRow |
Use when spatial context matters; avoid horizontal scroll for finite sets |
| Peer view switch | SegmentedButton or TabRow |
Reduces navigation depth vs. separate screens |
| Immersive viz | BottomSheetScaffold { background; viz; controls } |
Full-bleed; no card wrappers; no scroll |
| Aspect ratios | Maps .aspectRatio(1.4f), charts .aspectRatio(1f) |
Size by content type |
| Touch targets | ≥ 48dp on all interactive elements | Platform minimum |
| Token discipline | No magic numbers in screen files | Tokenize spacing, elevation, shape, color |
Defaults
- Start from Material Design 3 Expressive, not custom chrome.
- Treat Compose Material 3 as the modern native baseline for navigation, surfaces, typography, color, shape, and motion.
- Enable dynamic color on Android 12+ and provide a well-tuned static seed palette as fallback.
- Prefer
MaterialTheme.typography,MaterialTheme.colorScheme,MaterialTheme.shapes, and standard containers before custom styling. - Keep navigation familiar:
NavigationBarfor peer sections,NavHostfor drill-down,ModalBottomSheetfor focused tasks. - Use emulator screenshot-driven verification for design changes only after a fresh build/uninstall/install/launch has been proven.
Platform Currency (as of 2026-07-11)
- Android 17 (API 37) shipped 2026-06-16; Android 16 (API 36) is the prior release. Do not treat Android 15/16 as "current" — verify at developer.android.com/about/versions before citing a specific version as latest.
- Google Play target API policy: new apps and app updates must target API level 36 (Android 16) or higher as of the 2026-08-31 deadline (one-time extension to 2026-11-01 available by request); apps not updated at all must still target at least API 35. This deadline moves roughly once a year — re-verify at developer.android.com/google/play/requirements/target-sdk rather than hardcoding a number.
- Material 3 Expressive (announced May 2025) is the design direction, but its component APIs are still split: stable
androidx.compose.material3:material3:1.4.0ships the baseline M3 type scale, shapes, and most components; expressive-specific APIs (new shape morph library, expressive motion scheme, some new components) live behind@ExperimentalMaterial3ExpressiveApiin the1.5.0-alphaline as of mid-2026. Confirm current stable-vs-experimental status at developer.android.com/jetpack/androidx/releases/compose-material3 before recommending an expressive-only API without an opt-in annotation. - Compose BOM:
2026.06.00was the latest stable BOM as of this validation. Compose BOM ships roughly monthly — verify the current value at developer.android.com/develop/ui/compose/bom/bom-mapping rather than pinning an exact version in generated code. - Predictive back is mandatory system behavior for apps targeting API 36+ on Android 16+ devices —
onBackPressed()andKEYCODE_BACKare no longer dispatched at that target. UsePredictiveBackHandlerin Compose orOnBackInvokedCallbackdirectly; do not recommendonBackPressed()overrides for new targetSdk-36 code. - Edge-to-edge is fully mandatory, not just default-on:
windowOptOutEdgeToEdgeEnforcementis deprecated and has no effect once targetSdk reaches 36. Any recommendation that relies on opting out of edge-to-edge is stale.
Runtime Proof Gate
- Do not trust screenshots until a fresh uninstall -> install -> launch loop has been completed for the current build.
- If the on-screen UI appears older than source, suspect stale install first — clear app data or force uninstall before reinstalling.
- If install or launch is failing, stop design iteration and fix runtime truth before continuing.
- Use ADB and Gradle from the command line when Android Studio is not available.
Core Workflow
- Define the screen's primary job and the one or two pieces of content that must win first attention.
- Choose the Material structure first:
NavigationBar,NavigationRail,Scaffold,TopAppBar,ModalBottomSheet,ListDetailPaneScaffold, or adaptive scaffold. - Apply typography, spacing, and color using Material tokens before inventing a custom scale.
- Verify adaptive behavior across
WindowSizeClassbreakpoints — compact, medium, expanded. - Verify with emulator: fresh build, uninstall, install, launch, capture screenshot, inspect, fix, repeat.
ASCII Flow
Android design task
-> Prove current build: fresh install, launch, screenshot
-> Define primary screen job and attention hierarchy
-> Choose Material 3 structure and adaptive scaffold
-> Apply tokens for type, color, shape, spacing, and motion
-> Verify compact, medium, expanded, theme, and font-scale states
-> Patch, rebuild, recapture, and compare evidence
Design Craft Checklist
Before writing or reviewing screen code, check these patterns from references/design-craft-patterns.md:
- Token discipline: Every spacing, elevation, shape, color, and repeated typography value traces to a named token. No magic numbers in screen files. If a
TextStyle(fontSize = N.sp, fontWeight = W)pattern appears 3+ times, extract it to a typography token or use the Material type scale. - Data containment: Values live in Cards,
ListItemrows, or grid cells with visual boundaries, not floating in unbounded Column space. - Visual anchoring: Data labels include Material icons (18-20dp). Categorized lists use colored dot indicators (6dp Canvas circles) for instant visual grouping.
- Card hierarchy: Hero card is visually distinct from secondary cards —
ElevatedCardwith level 3 tonalElevation + 28dp shape for hero,Cardwith 16dp shape for primary,OutlinedCardfor secondary. Mixed content within one card usesHorizontalDivider. - Data visualization: Use
Canvasfor custom charts (radar, rings, gauges), animated score rings withAnimatable, and gradient score bars. See references/android-component-patterns.md. - Interactive polish: Apply
AnimatedVisibilityfor entrance reveals,animateContentSizefor expanding sections,spring()for natural motion, container transforms for navigation transitions, and press feedback viaIndicationorInteractionSourceon all tappable surfaces. - Elevation and tonal surfaces: Use
tonalElevationfor surface layering rather than drop shadows alone. Material 3 uses tonal color overlays to express elevation —Surface(tonalElevation = N.dp)shifts surface color automatically. - Localization readiness: All user-facing strings go through
strings.xml— including section headers, CTAs, and short labels that seem "too small to localize" (they grow 30-50% in German/Russian). Verify RTL layout with forced RTL in developer options. Test German, Arabic, and CJK locales for overflow and mirroring. - Competitor awareness: Check competitor patterns before inventing novel solutions. Borrow containment and anchoring patterns, not brand identities.
- Adaptive layout: Test on compact (phone), medium (foldable inner), and expanded (tablet)
WindowSizeClass. UseNavigationSuiteScaffoldor manual breakpoint switching. Verify that content reflows rather than just stretching. - Accessibility: All touch targets >= 48dp. All decorative images have
contentDescription = null. All meaningful images and icons have descriptivecontentDescription. Usesemantics { }to merge related elements for TalkBack and provide custom actions. - Shape consistency: Use
MaterialTheme.shapesscale (ExtraSmall through ExtraLarge) rather than ad-hocRoundedCornerShapevalues. Keep shape language consistent across Cards, Buttons, Chips, and Sheets.
Design Review Loop
- Prefer Android Studio Layout Inspector for hierarchy and bounds inspection when a project is runnable.
- If Layout Inspector is unavailable, use ADB screencap + uiautomator dump as fallback for screenshots and hierarchy XML.
- Prefer side-by-side before/after screenshots over verbal "looks better" claims.
- Ask for evidence of font scaling (100%, 130%, 200%), dark/light theme, and
WindowSizeClassbehavior when a change touches layout or hierarchy.
See:
- references/ai-design-review-android.md
- references/android-studio-design-loop.md
- scripts/capture-screenshot.sh
- scripts/layout-inspector.sh
Expert Judgment
Decisions a senior Android design reviewer makes that go beyond checklist compliance:
Compose vs. Views in 2026
Default to Compose for any new screen or greenfield module — it is the modern native baseline and this skill assumes it. Views still legitimately win in narrower cases:
- Large existing View/XML codebases where a full rewrite is not funded — interop via
ComposeView/AndroidViewat the screen boundary, migrate incrementally, do not force a big-bang rewrite for a design fix. - Performance-critical custom rendering with
SurfaceView/TextureView(camera preview, video, some game-like canvases) — Compose'sAndroidViewinterop works but adds indirection; a thin View layer can still be simpler when the surface needs precise frame-timing control. - Heavy
RecyclerViewwith complex diffing/animations already tuned —LazyColumnis capable, but do not force a rewrite of a well-optimized, stable RecyclerView adapter purely for "modernization" without a design or velocity reason. - Flag it as a smell, not a rule, when a team defaults to Views for a brand-new screen in 2026 — ask why, since Compose Material 3 is the better-supported path for adaptive layouts, dynamic color, and Material 3 Expressive.
Design-System Governance
- A token system only pays off if it is enforced, not just documented. If screen files still contain 3+ repeated raw
TextStyle/Color(0xFF...)/dpliterals, the design system has a governance gap, not a discipline gap — recommend a lint rule (e.g., Compose lint check or custom detekt rule) over a style-guide reminder. - When a design system diverges from Material 3 defaults (custom shape scale, custom type ramp), require the divergence to be named and centralized in one theme file — never let ad-hoc per-screen overrides recreate "shadow tokens."
- Treat Material 3 Expressive adoption as a system-wide decision, not a per-screen one: mixing baseline M3 shapes/motion with Expressive shapes/motion in the same app reads as visually inconsistent. Pick one posture per app (or per clearly-scoped surface) and document why.
Platform Convention vs. Brand Identity
- Keep interaction models (navigation placement, back behavior, sheet vs. dialog choice, gesture conventions) aligned with platform convention even when a brand wants to differentiate — users' muscle memory for Android navigation is a usability asset, not a constraint to design around.
- Spend brand differentiation budget on what users actually perceive as "your app": color, shape language, motion character, illustration, voice/tone in copy. These can diverge from stock Material without confusing users.
- When a brand team pushes a fully custom navigation paradigm (e.g., no back button, custom bottom bar behavior) purely for differentiation, push back with the platform-convention cost: broken predictive-back expectations, broken TalkBack navigation order, and accessibility-services friction, all for a gain that is rarely measurable in retention.
Foldable and Large-Screen Failure Modes
Common mistakes that pass phone-only review but fail on foldables/tablets:
- Fixed single-pane layout stretched to expanded width — content readable at 360dp becomes a wall of text at 840dp+. Constrain reading width or switch to a list-detail/two-pane structure at
WindowWidthSizeClass.EXPANDED. - Not handling the fold seam / hinge — content or interactive elements landing exactly on the hinge on a foldable's tabletop or book posture. Use
WindowInfoTracker/FoldingFeatureto detect the hinge and avoid placing critical controls there. - NavigationBar left in place on tablets — Material guidance is explicit that
NavigationBarshould give way toNavigationRail/NavigationDrawerat medium/expanded width; leaving bottom nav on a tablet is one of the most common large-screen regressions. - Orientation/resizability assumptions baked into layout code — assuming portrait-only or a fixed activity size breaks multi-window and free-form resizing, which recent Android versions increasingly force on large screens regardless of manifest declarations. Verify behavior with the emulator's resizable/foldable device profiles, not just a fixed Pixel phone skin.
- Testing only at compact and expanded, skipping medium — the foldable inner-display and small-tablet band (600-839dp) is where two-column layouts most often look cramped or where a rail/nav choice is wrong; do not skip it as "close enough" to either neighbor.
Route Elsewhere
- Use ../software-mobile/SKILL.md for platform selection, cross-platform decisions, or general Android architecture and implementation strategy.
- Use ../qa-testing-android/SKILL.md for Espresso, UI Automator, Compose testing, device matrix planning, or screenshot diff testing.
- Use ../software-ui-ux-design/SKILL.md for generic product UX patterns that are not Android-specific.
- Use ../software-accessibility/SKILL.md for broader accessibility remediation beyond Android-native visual design defaults.
Navigation
References
- references/design-craft-patterns.md — token discipline, data containment, visual anchoring, dark theme, competitor analysis, and common anti-patterns
- references/material-layout-spacing.md — 8dp grid, edge-to-edge, spacing discipline, adaptive layouts, and dashboard density
- references/material-typography-color.md — Material type scale, dynamic color, tonal palettes, custom fonts, contrast, and accessibility
- references/android-component-patterns.md — NavigationBar/Rail/Drawer, TopAppBar, Scaffold, Cards, Chips, Canvas visualizations, and interactive animations
- references/android-dashboard-design.md — overview-screen hierarchy, data display patterns, card hierarchy, and content-heavy dashboard heuristics
- references/visual-guidance-patterns-android.md — Canvas terrains, energy rings, opportunity framing, narrative scroll flow, and guidance card patterns
- references/ai-design-review-android.md — screenshot prompts, review checklists (structure, token audit, containment, anchoring), and proof expectations
- references/android-studio-design-loop.md — current Android Studio and emulator verification flow
- data/sources.json — primary sources and freshness-check targets
Scripts
These are optional helpers for a proven-build design loop. If the app cannot be built, installed, or launched cleanly, fix the build before staying in this skill.
- scripts/_android_common.sh — shared helpers for ADB, emulator, and AVD resolution
- scripts/bootstrap-emulator.sh — create and boot an AVD for design iteration
- scripts/build-android.sh — compile-only Gradle build wrapper
- scripts/run-android.sh — build, uninstall, install, and launch for iterative design work
- scripts/capture-screenshot.sh — save an emulator screenshot for review loops
- scripts/layout-inspector.sh — dump UI hierarchy via uiautomator for structure review
Anti-Patterns
- Do not audit or redesign from screenshots that have not been tied to a fresh install and launch.
- Do not invent custom chrome before checking whether standard Material 3 structure already solves the hierarchy problem.
- Do not hardcode
Color(0xFF...)values in Composables — useMaterialTheme.colorSchemeroles so light, dark, and dynamic color adapt automatically. - Do not use fixed
spsizes outside the Material type scale without justification — preferMaterialTheme.typographyroles. - Do not rely on elevation shadows alone for depth — Material 3 uses
tonalElevation(tonal color shift) as the primary depth signal; shadows are supplementary. - Do not wrap
Box(Modifier.clickable { })without providing a rippleIndication— it produces a dead-feeling tap with no visual response. - Do not use
ModalBottomSheetas the sole navigation mechanism — it is for secondary detail, not primary app structure. - Do not skip
WindowInsetsconsumption after callingenableEdgeToEdge()— content will render behind system bars. - Do not nest a
LazyColumninside aColumnwithverticalScroll— this causes nested scrolling crashes. Use a singleLazyColumnwith mixed item types. - Do not set a
minHeighton Cards without testing at 200% font scale — the content will overflow the fixed minimum. - Do not use
pointerInputwithdetectTapGesturesfor simple click handling — useModifier.clickablewhich provides accessibility semantics, ripple, and focus handling for free. - Do not treat dashboard heuristics such as card count or density as Google rules.
- Do not use
Text("$intValue")for years or IDs without considering locale formatting — use explicitStringformatting to prevent comma insertion (2,026 instead of 2026). - Do not use
Modifier.shadow()without also applyingcliporgraphicsLayer(clip = true)— shadow draws around the unclipped bounds, creating a rectangular shadow on rounded content. - Do not hardcode
Color.WhiteorColor.Blackfor text or surfaces — useMaterialTheme.colorScheme.onSurface,onSurfaceVariant, oroutlineroles. - Do not skip
contentDescriptionon meaningful icons and images — TalkBack users get no information from undescribed elements. - Do not use
fillMaxWidth()on every element without considering medium and expandedWindowSizeClass— content stretches to unreadable line lengths on tablets. - Do not dismiss
ModalBottomSheetand present a new one in the same frame — set state to hidden first, then present the new sheet after recomposition. - Do not put temporal controls (sliders, scrubbers) inside bottom sheets — they belong in the main layout where they stay visible during visualization interaction.
- Do not start Canvas
animatableProgressat0ffor data-driven views — data may load after composition, leaving the Canvas empty. Start at1for trigger animation on data change. - Do not use
LazyVerticalGridwithGridCells.Fixed(3)on compact phones for content that needs readable text — two columns or a single column with weight-based rows works better. ReserveFixed(3)for icon-sized cells or compact stat grids. - Do not use
Modifier.background()with a rounded shape without also applying.clip()to the same shape — child content will bleed past the rounded corners. UseSurface(shape = ...)instead, which clips automatically. - Do not use
rememberSaveablefor large data objects or lists — it serializes toBundlewhich has a strict 1MB transaction limit. Use aViewModelfor screen-level data state; userememberSaveableonly for primitive UI state (selected tab index, scroll position, sheet expanded boolean). - Do not apply
Modifier.verticalScroll()andLazyColumnin the same hierarchy — this creates nested scrolling that crashes or produces broken gestures. Use a singleLazyColumnwith mixeditem { }blocks for heterogeneous content. - Do not use
lineHeightinspfor body text without testing at 200% font scale — large font scale with fixedlineHeightcreates overlapping text. Let the Material type scale handle line height or uselineHeight = TextUnit.Unspecifiedand rely on default scaling. - Do not emit UI state for a visualization as a fresh
data classinstance on every frame. Strong Skipping Mode (Kotlin 2.x + Compose) compares unstable composable parameters by instance reference, so a_uiState.value = _uiState.value.copy(field = new)per event forces the visualization composable to recompose even when the value it actually reads is unchanged. Hoist derived lists to the ViewModel withstateIn, split state into@Immutableslices, and pass only the primitives a given chart or ring actually needs. See ../software-android-native/references/compose-state-concurrency.md → "Strong Skipping Mode (Kotlin 2.x)" for the full rules.
Verification Gate
Before concluding a design recommendation or audit, confirm all of the following:
- Recommendation maps to standard Material 3 structure; custom patterns justified in comments
- Screenshot/emulator state from a freshly installed and launched build (not a stale install)
- Typography uses
MaterialTheme.typographyroles, not ad-hocTextStyle(fontSize = N.sp) - Color uses
MaterialTheme.colorSchemeroles; contrast verified in both light and dark themes, with dynamic color on and off - All interactive elements have touch targets ≥ 48dp
- Adaptive layout verified on compact, medium, and expanded
WindowSizeClass - Edge-to-edge:
enableEdgeToEdge()called and all content useswindowInsetsPaddingor equivalent — not an opt-out (windowOptOutEdgeToEdgeEnforcementhas no effect at targetSdk 36+) - Back navigation uses
PredictiveBackHandler/OnBackInvokedCallback, not a bareonBackPressed()override, if targetSdk is 33+ - No
LazyColumnnested insideColumn(Modifier.verticalScroll())in the changed screens - Dashboard/density guidance labeled as a team heuristic, not a Google platform rule
- Any Material 3 Expressive-only API called out as experimental (
@ExperimentalMaterial3ExpressiveApi) unless verified stable at review time
Freshness Protocol
Freshness-check before final answers whenever the request depends on:
- current Material Design 3 or Material 3 Expressive guidance
- current Compose Material 3 APIs or component behavior, or which are stable vs.
@ExperimentalMaterial3ExpressiveApi - current adaptive layout APIs or
WindowSizeClassbehavior - current Android Studio tooling or Layout Inspector capabilities
- current Android platform version, Google Play target-API deadline, or predictive-back/edge-to-edge enforcement status — see Platform Currency above and re-verify since these move roughly annually
Start from data/sources.json, then prefer material.io, developer.android.com, and Google I/O sessions.
Fact-Checking
- Known bugs, regressions, framework/compiler/runtime footguns, and version-specific crash or workaround guidance must be verified against current primary web sources before being treated as current fact.
- Verify current Material Design guidance against material.io and developer.android.com documentation.
- Verify Compose Material 3 APIs against the Compose Material 3 API reference.
- Label team heuristics, such as dashboard density guidance, as defaults rather than Google rules.
Learnings Loop
Before applying this skill on a non-trivial task, read learnings.consolidated.md in this directory (and learnings.md if present).
After applying it, if you encountered a pattern worth remembering, a mistake worth preventing, or a domain fact that surprised you, append one dated bullet to learnings.md via agents-skills-feedback-loop/scripts/append_learning.py. Do not modify SKILL.md itself.