How to use
- Copy the installation command and review the source package before installing it in your own agent environment.
- Check the source document for required tools, credentials and supported hosts.
- Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/karanb05/mobile-flutter-design-skill --skill mobile-flutter-designBefore you start
- Installation does not include a model subscription, API allowance or permission to access your files.
- Repository stars and installation counts describe activity, not an independent quality or security test.
Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.
Flutter iOS Design
Adapts Apple's Human Interface Guidelines (HIG) to Flutter. The HIG principles are framework-agnostic; this skill re-expresses them in idiomatic Flutter so a Flutter app can feel native on iOS without leaving Dart. Converted from the SwiftUI-based mobile-ios-design skill.
When to Use This Skill
- Designing/refining Flutter screens that must feel native on iOS
- Choosing Cupertino vs. Material widgets for an iOS-leaning app
- Getting spacing, typography, and hierarchy to HIG standards in Flutter
- Implementing iOS-style navigation (stacks, tabs, bottom sheets) in Flutter
- Supporting Dynamic Type (text scaling), Dark Mode, and accessibility
- Making glanceable, uncluttered dashboards and lists
Cupertino vs. Material — the first decision
Flutter ships two design languages. Pick deliberately:
- Material (`MaterialApp`, `Scaffold`, `NavigationBar`) — the pragmatic
default for cross-platform apps. Looks clean on iOS; not pixel-native but users accept it. If the app already commits to Material, stay in Material and apply HIG principles (spacing, hierarchy, restraint) rather than swapping widgets. Don't mix half-and-half — inconsistency reads as broken.
- Cupertino (`CupertinoApp`, `CupertinoPageScaffold`, `CupertinoNavigationBar`)
— pixel-native iOS look (system fonts, iOS transitions, sliding back gesture). Use when "feels exactly like an Apple app" is a hard requirement, or for a specific surface (a settings screen, an action sheet).
- Hybrid — Material shell + Cupertino for specific interactions
(showCupertinoModalPopup for action sheets, CupertinoContextMenu). Fine when intentional and consistent.
This project (FieldFlowSales mobile) is a Material app (NavigationBar,showModalBottomSheet, custom cards). Apply HIG at the principle level here; reach for Cupertino widgets only for genuinely iOS-idiomatic moments.
Core Concepts
1. HIG Principles (framework-agnostic)
- Clarity — legible text, precise icons, subtle adornment. Prefer content
over chrome. In Flutter: lean on Theme.of(context).textTheme, keep borders and shadows light, avoid decorative gradients competing with content.
- Deference — the UI helps users understand content without competing with
it. Translate to restraint: one accent color per surface, generous whitespace, no card-in-card-in-card nesting.
- Depth — layers and motion convey hierarchy. In Flutter: elevation/shadow
for cards, showModalBottomSheet sliding up for transient tasks, hero/route transitions for drill-down.
2. Layout — SwiftUI → Flutter
| SwiftUI | Flutter |
|---|---|
VStack(alignment:spacing:) | Column(crossAxisAlignment:, children:[…, SizedBox(height:)…]) |
HStack | Row |
ZStack | Stack |
Spacer() | Spacer() or Expanded |
.padding() | Padding(padding: EdgeInsets…) / Container(padding:) |
LazyVStack / List | ListView / ListView.builder |
LazyVGrid(adaptive) | GridView.builder(gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 200)) |
LazyVGrid(fixed 3) | GridView.count(crossAxisCount: 3) |
// VStack(alignment: .leading, spacing: 12) equivalent
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title', style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 12),
Text('Subtitle',
style: Theme.of(context).textTheme.bodyMedium
?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant)),
],
)
// HStack with Spacer + trailing accent
Row(
children: [
Icon(Icons.star, color: Colors.amber),
const SizedBox(width: 8),
const Text('Featured'),
const Spacer(),
Text('View All', style: TextStyle(color: Theme.of(context).colorScheme.primary)),
],
)Spacing scale: HIG leans on multiples of 4/8. Use a consistent scale (4, 8, 12, 16, 24) rather than arbitrary values. Standard screen edge padding is 16.
3. Navigation
| SwiftUI | Flutter |
|---|---|
NavigationStack + NavigationLink | Navigator + MaterialPageRoute (or go_router) |
.navigationTitle | AppBar(title:) |
TabView | Scaffold(bottomNavigationBar: NavigationBar) + IndexedStack |
.sheet | showModalBottomSheet |
.confirmationDialog | showModalBottomSheet of actions, or showCupertinoModalPopup |
.fullScreenCover | Navigator.push with fullscreenDialog: true |
Full patterns and code in references/flutter-navigation.md. Key HIG rule: push for drill-down (a back stack), sheet for a transient/self-contained task, tabs for peer sections. Keep tab pages alive with IndexedStack so switching doesn't rebuild/refetch (this app learned that the hard way — it fixed a tab flicker).
4. System Integration
- Icons: SF Symbols → Flutter
Icons(Material) orCupertinoIcons. For an
iOS feel use CupertinoIcons; for a Material app, Icons is consistent. Pick one set per app.
- Dynamic Type: SwiftUI scales automatically; Flutter needs care. Never
hardcode font sizes for body copy where you can use textTheme. Respect the user's setting via MediaQuery.textScalerOf(context) — don't clamp it to 1.0 (that breaks accessibility). Test at 200% text size; ensure rows grow, not clip.
- Haptics:
HapticFeedback.selectionClick()/.lightImpact()on
meaningful actions (toggle, pull-to-refresh complete) — iOS users expect it.
5. Visual Design
- Semantic colors (dark-mode safe): SwiftUI's
.primary/.secondary→
Flutter's ColorScheme. Use Theme.of(context).colorScheme.onSurface, onSurfaceVariant, surface, primary instead of literal Colors.black/ Colors.grey.shadeXXX. Literal colors are the #1 cause of broken dark mode. If the app is light-only today, still prefer colorScheme so dark mode is a theme change, not a rewrite.
- Materials/blur: SwiftUI
.ultraThinMaterial→BackdropFilterwith
ImageFilter.blur behind a translucent color (use sparingly; it's costly).
- Elevation: card shadow via `BoxShadow(color: Colors.black.withValues(alpha:
0.06), blurRadius: 8, offset: Offset(0, 4)) or Material(elevation:)`. HIG shadows are subtle — low opacity, soft blur. Avoid heavy drop shadows.
- Corner radius: 12 for cards, 20+ for pills/sheets, matching iOS softness.
Quick Start Component (SwiftUI FeatureCard → Flutter)
class FeatureCard extends StatelessWidget {
final String title;
final String description;
final IconData icon;
final VoidCallback? onTap;
const FeatureCard({
super.key,
required this.title,
required this.description,
required this.icon,
this.onTap,
});
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: scheme.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.05),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Row(
children: [
Container(
width: 44,
height: 44,
alignment: Alignment.center,
decoration: BoxDecoration(
color: scheme.primary.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
child: Icon(icon, color: scheme.primary),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 4),
Text(
description,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyMedium
?.copyWith(color: scheme.onSurfaceVariant),
),
],
),
),
Icon(Icons.chevron_right, color: scheme.outline),
],
),
),
);
}
}Best Practices (Flutter-adapted)
- Prefer `ColorScheme`/`textTheme` over literals — automatic dark mode and
consistent typography. Reserve literal colors for brand accents only.
- One icon set per app (
IconsorCupertinoIcons) — don't mix. - Respect text scaling — use
textTheme, don't hardcode body sizes, don't
clamp textScaler. Let rows grow.
- Add semantics — wrap icon-only buttons with
Semantics(label:)or use
IconButton(tooltip:); label meaningful images. Test with TalkBack/VoiceOver.
- Respect safe areas — wrap edge content in
SafeArea; don't hardcode
status-bar/home-indicator padding.
- Keep tab pages alive —
IndexedStack(orAutomaticKeepAliveClientMixin)
so switching tabs doesn't refetch and flicker.
- Lazy lists —
ListView.builder/GridView.builderfor long content, never
a Column of hundreds of children.
- Glanceable first — put what a user needs at a glance at the top; collapse
detail behind taps (e.g. a summary row that expands). Cards should be slim.
- Test on device — haptics, scroll physics, and true colors don't show in a
simulator screenshot.
Common Issues (Flutter)
- Broken dark mode — literal
Colors.black/Colors.grey.shadeXXX. Use
colorScheme.
- Clipped text at large font sizes — fixed heights on rows containing text;
let them size to content, use Flexible/Expanded.
- Jank on long lists — non-lazy
Column/ListView(children:[…]); switch to
.builder.
- Overflowing dialogs/sheets — unbounded content in a
Dialog; give the body
overflow-y via a scroll view and cap tall inner lists (this app hit exactly this in a modal — DialogContent was display:grid, so a flex child didn't scroll; the fix was overflow on the content itself + a height-capped list).
- Tab flicker / lost scroll — recreating tab pages on switch; use
IndexedStack.
- Nested-scroll gesture conflict — a scrollable inside a scrollable fighting
for the drag. Avoid unless the inner region genuinely needs its own scroll; prefer letting the page scroll.
References
references/flutter-navigation.md— stacks, tabs, bottom sheets, dialogs,
deep links, transitions (SwiftUI navigation → Flutter).
references/flutter-components.md— lists, forms/inputs, buttons/menus,
sheets, loading/skeletons, async images, animations, gestures (SwiftUI components → Flutter).

