| name | layout |
| description | watchOS layout: glanceable design, watch-sized stacks, containerRelativeFrame, 1-2 second interaction principles. Use when working on shared watchOS patterns related to layout. |
SwiftUI Layout (watchOS)
Glanceable design: users interact with Apple Watch for 1-2 seconds. Every view must communicate its purpose instantly.
Watch Screen Constraints
- Screen sizes: 40mm (162pt), 41mm (176pt), 44mm (184pt), 45mm (198pt), 49mm Ultra (205pt)
- Always design for the smallest screen, let larger screens breathe
- No landscape orientation — always portrait
- No split views, no multi-column layouts
Layout Principles
Vertical Stacking
VStack(spacing: 8) {
Text("Heart Rate")
.font(AppTheme.Fonts.caption2)
.foregroundStyle(.secondary)
Text("72")
.font(AppTheme.Fonts.largeTitle)
Text("BPM")
.font(AppTheme.Fonts.caption)
.foregroundStyle(.secondary)
}
Full-Width Elements
Button("Start Workout") {
startWorkout()
}
.buttonStyle(.borderedProminent)
containerRelativeFrame (preferred over GeometryReader)
Image("chart")
.resizable()
.containerRelativeFrame(.horizontal) { width, _ in
width * 0.9
}
.aspectRatio(contentMode: .fit)
View Structure
Prefer Modifiers Over Conditional Views
SomeView()
.opacity(isVisible ? 1 : 0)
if isVisible {
SomeView()
}
Extract Subviews Into Separate Structs
struct MetricDisplay: View {
let value: Int
let unit: String
var body: some View {
VStack {
Text("\(value)")
.font(AppTheme.Fonts.title2)
Text(unit)
.font(AppTheme.Fonts.caption2)
.foregroundStyle(.secondary)
}
}
}
What NOT to Use on watchOS
- No
GeometryReader — use containerRelativeFrame or let stacks fill naturally
- No
UIScreen.main.bounds — doesn't exist on watchOS
- No size classes — watch has one size class
- No
NavigationSplitView — watch is single-column only
- No adaptive grids with many columns — use simple
VStack or single-column List
- No
.frame(maxWidth: 700) readability constraints — the screen is already small
- No
AnyLayout switching — there's only one layout direction on watch
Layout Rules
- Keep views shallow — 2-3 levels of nesting maximum
- Use
List for scrollable content, ScrollView for custom layouts
- Large text (
.title, .largeTitle) for primary information
- Small text (
.caption, .caption2) for labels and secondary info
- Minimum tap target: 44pt (Apple requirement, critical on small screen)
- Use
@ScaledMetric for custom dimensions that respect Dynamic Type