swiftship/internal/skills/data/ui/adaptive-layout/SKILL.md
Adaptive layout for iPad and universal apps: NavigationSplitView, size classes, horizontalSizeClass, presentations, HIG compliance. Use when building iPad-optimized layouts, supporting multiple screen sizes, or adapting UI for iPhone+iPad. Triggers: iPad, universal, NavigationSplitView, horizontalSizeClass, size class, adaptive.
npx skillsauth add abdullah4ai/apple-developer-toolkit adaptive-layoutInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Let SwiftUI adapt automatically. Never check UIDevice.current.userInterfaceIdiom or UIScreen.main.bounds for layout decisions. Use size classes and adaptive containers instead.
Use NavigationSplitView for ANY list-detail flow. It collapses to NavigationStack on iPhone and shows sidebar+detail on iPad — zero conditional code.
@State private var selectedItem: Item?
NavigationSplitView {
List(items, selection: $selectedItem) { item in
NavigationLink(value: item) { ItemRow(item: item) }
}
.navigationTitle("Items")
} detail: {
if let selectedItem {
ItemDetailView(item: selectedItem)
} else {
ContentUnavailableView("Select an Item", systemImage: "doc")
}
}
Three-column pattern (sidebar categories → list → detail):
NavigationSplitView {
List(categories, selection: $selectedCategory) { ... }
} content: {
List(filteredItems, selection: $selectedItem) { ... }
} detail: {
if let selectedItem { DetailView(item: selectedItem) }
else { ContentUnavailableView(...) }
}
Use NavigationStack ONLY for purely linear flows (onboarding, checkout).
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
| Context | horizontalSizeClass |
|---|---|
| iPhone portrait | .compact |
| iPhone landscape | .compact |
| iPad full-screen | .regular |
| iPad Split View (narrow) | .compact |
| iPad Split View (wide) | .regular |
Critical: iPad in Split View multitasking can report .compact. This is why UIDevice.current is wrong — always use size classes.
@Environment(\.horizontalSizeClass) private var sizeClass
var body: some View {
let layout = sizeClass == .compact
? AnyLayout(VStackLayout(spacing: 16))
: AnyLayout(HStackLayout(spacing: 24))
layout {
ContentBlockA()
ContentBlockB()
}
}
Use when the decision is purely about available space — no environment reading needed:
ViewThatFits {
HStack(spacing: 16) { icon; title; subtitle; actionButton }
VStack(alignment: .leading, spacing: 8) {
HStack { icon; title }
subtitle
actionButton
}
}
When to use which:
ViewThatFits → component-level (a card, a header, a toolbar item)horizontalSizeClass → screen-level (different page structures)Always use GridItem(.adaptive(minimum:maximum:)) — never hardcode column counts:
LazyVGrid(
columns: [GridItem(.adaptive(minimum: 160, maximum: 320))],
spacing: 16
) {
ForEach(items) { item in CardView(item: item) }
}
.padding()
Automatically: 2 columns on iPhone, 3-4 on iPad portrait, 4-6 on iPad landscape.
.popover(isPresented: $showOptions) {
OptionsView()
}
.sheet(isPresented: $showSheet) {
SheetContent()
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
}
Always use .confirmationDialog — it becomes an action sheet on iPhone, popover on iPad:
.confirmationDialog("Options", isPresented: $showDialog) {
Button("Option A") { }
Button("Cancel", role: .cancel) { }
}
.padding() with no arguments — SwiftUI applies 16pt on iPhone, 20pt on iPad automatically.ScrollView {
content
.frame(maxWidth: 700)
.frame(maxWidth: .infinity)
}
@ScaledMetric for custom dimensions that respect Dynamic Type:@ScaledMetric(relativeTo: .body) private var iconSize: CGFloat = 24
Prefer containerRelativeFrame over GeometryReader:
Image("photo")
.containerRelativeFrame(.horizontal, count: 3, span: 1, spacing: 16)
Reserve GeometryReader only for complex calculations (parallax, custom alignment).
UIDevice.current.userInterfaceIdiom for layout — breaks iPad multitaskingUIScreen.main.bounds for sizing — doesn't respond to multitasking#if targetEnvironment for layout decisions.frame(width: 375)).adaptive(minimum:).font(.body), .font(.title))NavigationSplitView for iPad empty state.popover for contextual actions — SwiftUI auto-adapts.leading/.trailing — never .left/.righttools
Apple platform skill for docs, WWDC lookup, App Store Connect work, and SwiftUI app generation. Use repo-local `node cli.js` for Apple docs and WWDC search, `appledev store` for App Store Connect workflows, and `appledev build` for app scaffolding or fix loops on macOS. USE WHEN: Apple APIs, WWDC sessions, TestFlight/App Store tasks, or building/fixing Apple-platform apps. DON'T USE WHEN: non-Apple platforms, generic backend work, or general web research. EDGE CASES: docs-only queries use `node cli.js` in this repo, not `appledev`; release workflows use `appledev store`; app scaffolding uses `appledev build`; rules-only requests can read `references/ios-rules/` or `references/swiftui-guides/` progressively without invoking binaries.
tools
All-in-one Apple developer skill with three integrated tools shipped as a single unified binary. (1) Documentation search across Apple frameworks, symbols, and 1,267 WWDC sessions from 2014-2025. No credentials needed. (2) App Store Connect CLI with 120+ commands covering builds (find/wait/upload), TestFlight, pre-submission validate, submissions, signing, subscriptions (family-sharable), IAP, analytics, Xcode Cloud, metadata workflows, release pipeline dashboard, insights, win-back offers, promoted purchases, product pages, nominations, accessibility declarations, pre-orders, pricing filters, localizations update, diff, webhooks with local receiver, workflow automation, and more. Requires App Store Connect API key. (3) Multi-platform app builder (iOS/watchOS/tvOS/iPad/macOS/visionOS) that generates complete Swift/SwiftUI apps from natural language with auto-fix, simulator launch, interactive chat mode, and open-in-Xcode. Requires an LLM API key and Xcode. Includes 38 iOS development rules and 12 SwiftUI best practice guides for Liquid Glass, navigation, state management, and modern APIs. All three tools ship as one binary (appledev). USE WHEN: Apple API docs, App Store Connect management, WWDC lookup, or building iOS/watchOS/tvOS/macOS/visionOS apps from scratch. DON'T USE WHEN: non-Apple platforms or general coding.
testing
watchOS complications: WidgetKit complication families, accessory sizes, timeline providers for watch face. Use when implementing watchOS-specific patterns related to widgets.
development
watchOS haptic feedback: WKInterfaceDevice preset haptic types for wrist-based feedback. Use when implementing watchOS-specific patterns related to haptics.