axiom-swiftui-containers-ref

axiom-swiftui-containers-ref

热门

Reference — SwiftUI stacks, grids, outlines, and scroll enhancements through iOS 26

415Star
41Fork
更新于 2/5/2026
SKILL.md
readonly只读
name
axiom-swiftui-containers-ref
description

Reference — SwiftUI stacks, grids, outlines, and scroll enhancements through iOS 26

version
"1.2.0"

SwiftUI Containers Reference

Stacks, grids, outlines, and scroll enhancements. iOS 14 through iOS 26.

Sources: WWDC 2020-10031, 2022-10056, 2023-10148, 2024-10144, 2025-256

Quick Decision

Use Case Container iOS
Fixed views vertical/horizontal VStack / HStack 13+
Overlapping views ZStack 13+
Large scrollable list LazyVStack / LazyHStack 14+
Multi-column grid LazyVGrid 14+
Multi-row grid (horizontal) LazyHGrid 14+
Static grid, precise alignment Grid 16+
Hierarchical data (tree) List with children: 14+
Custom hierarchies OutlineGroup 14+
Show/hide content DisclosureGroup 14+

Part 1: Stacks

VStack, HStack, ZStack

VStack(alignment: .leading, spacing: 12) {
    Text("Title")
    Text("Subtitle")
}

HStack(alignment: .top, spacing: 8) {
    Image(systemName: "star")
    Text("Rating")
}

ZStack(alignment: .bottomTrailing) {
    Image("photo")
    Badge()
}

ZStack alignments: .center (default), .top, .bottom, .leading, .trailing, .topLeading, .topTrailing, .bottomLeading, .bottomTrailing

Spacer

HStack {
    Text("Left")
    Spacer()
    Text("Right")
}

Spacer(minLength: 20)  // Minimum size

LazyVStack, LazyHStack (iOS 14+)

Render children only when visible. Use inside ScrollView.

ScrollView {
    LazyVStack(spacing: 0) {
        ForEach(items) { item in
            ItemRow(item: item)
        }
    }
}

Pinned Section Headers

ScrollView {
    LazyVStack(pinnedViews: [.sectionHeaders]) {
        ForEach(sections) { section in
            Section(header: SectionHeader(section)) {
                ForEach(section.items) { item in
                    ItemRow(item: item)
                }
            }
        }
    }
}

Part 2: Grids

Grid (iOS 16+)

Non-lazy grid with precise alignment. Loads all views at once.

Grid(alignment: .leading, horizontalSpacing: 10, verticalSpacing: 10) {
    GridRow {
        Text("Name")
        TextField("Enter name", text: $name)
    }
    GridRow {
        Text("Email")
        TextField("Enter email", text: $email)
    }
}

Modifiers:

  • gridCellColumns(_:) — Span multiple columns
  • gridColumnAlignment(_:) — Override column alignment
Grid {
    GridRow {
        Text("Header").gridCellColumns(2)
    }
    GridRow {
        Text("Left")
        Text("Right").gridColumnAlignment(.trailing)
    }
}

LazyVGrid (iOS 14+)

Vertical-scrolling grid. Define columns; rows grow unbounded.

let columns = [
    GridItem(.flexible()),
    GridItem(.flexible()),
    GridItem(.flexible())
]

ScrollView {
    LazyVGrid(columns: columns, spacing: 16) {
        ForEach(items) { item in
            ItemCard(item: item)
        }
    }
}

LazyHGrid (iOS 14+)

Horizontal-scrolling grid. Define rows; columns grow unbounded.

let rows = [GridItem(.fixed(100)), GridItem(.fixed(100))]

ScrollView(.horizontal) {
    LazyHGrid(rows: rows, spacing: 16) {
        ForEach(items) { item in
            ItemCard(item: item)
        }
    }
}

GridItem.Size

Size Behavior
.fixed(CGFloat) Exact width/height
.flexible(minimum:maximum:) Fills space equally
.adaptive(minimum:maximum:) Creates as many as fit
// Adaptive: responsive column count
let columns = [GridItem(.adaptive(minimum: 150))]

Part 3: Outlines

List with Hierarchical Data (iOS 14+)

struct FileItem: Identifiable {
    let id = UUID()
    var name: String
    var children: [FileItem]?  // nil = leaf
}

List(files, children: \.children) { file in
    Label(file.name, systemImage: file.children != nil ? "folder" : "doc")
}
.listStyle(.sidebar)

OutlineGroup (iOS 14+)

For custom hierarchical layouts outside List.

List {
    ForEach(canvases) { canvas in
        Section(header: Text(canvas.name)) {
            OutlineGroup(canvas.graphics, children: \.children) { graphic in
                GraphicRow(graphic: graphic)
            }
        }
    }
}

DisclosureGroup (iOS 14+)

@State private var isExpanded = false

DisclosureGroup("Advanced Options", isExpanded: $isExpanded) {
    Toggle("Enable Feature", isOn: $feature)
    Slider(value: $intensity)
}

Part 4: Common Patterns

Photo Grid

let columns = [GridItem(.adaptive(minimum: 100), spacing: 2)]

ScrollView {
    LazyVGrid(columns: columns, spacing: 2) {
        ForEach(photos) { photo in
            AsyncImage(url: photo.thumbnailURL) { image in
                image.resizable().aspectRatio(1, contentMode: .fill)
            } placeholder: { Color.gray }
            .aspectRatio(1, contentMode: .fill)
            .clipped()
        }
    }
}

Horizontal Carousel

ScrollView(.horizontal, showsIndicators: false) {
    LazyHStack(spacing: 16) {
        ForEach(items) { item in
            CarouselCard(item: item).frame(width: 280)
        }
    }
    .padding(.horizontal)
}

File Browser

List(selection: $selection) {
    OutlineGroup(rootItems, children: \.children) { item in
        Label {
            Text(item.name)
        } icon: {
            Image(systemName: item.children != nil ? "folder.fill" : "doc.fill")
        }
    }
}
.listStyle(.sidebar)

Part 5: Performance

When to Use Lazy

Size Scrollable? Use
1-20 No VStack/HStack
1-20 Yes VStack/HStack in ScrollView
20-100 Yes LazyVStack/LazyHStack
100+ Yes LazyVStack/LazyHStack or List
Grid <50 No Grid
Grid 50+ Yes LazyVGrid/LazyHGrid

Cache GridItem arrays — define outside body:

struct ContentView: View {
    let columns = [GridItem(.adaptive(minimum: 150))]  // ✅
    var body: some View {
        LazyVGrid(columns: columns) { ... }
    }
}

iOS 26 Performance

  • 6x faster list loading for 100k+ items
  • 16x faster list updates
  • Reduced dropped frames in scrolling
  • Nested ScrollViews with lazy stacks now properly defer loading:
ScrollView(.horizontal) {
    LazyHStack {
        ForEach(photoSets) { set in
            ScrollView(.vertical) {
                LazyVStack {
                    ForEach(set.photos) { PhotoView(photo: $0) }
                }
            }
        }
    }
}

Part 6: Scroll Enhancements

containerRelativeFrame (iOS 17+)

Size views relative to scroll container.

ScrollView(.horizontal) {
    LazyHStack {
        ForEach(cards) { card in
            CardView(card: card)
                .containerRelativeFrame(.horizontal, count: 3, span: 1, spacing: 16)
        }
    }
}

scrollTargetLayout (iOS 17+)

Enable snapping.

ScrollView(.horizontal) {
    LazyHStack {
        ForEach(items) { ItemCard(item: $0) }
    }
    .scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)

scrollPosition (iOS 17+)

Track topmost visible item. Requires .id() on each item.

@State private var position: Item.ID?

ScrollView {
    LazyVStack {
        ForEach(items) { item in
            ItemRow(item: item).id(item.id)
        }
    }
}
.scrollPosition(id: $position)

scrollTransition (iOS 17+)

.scrollTransition { content, phase in
    content
        .opacity(1 - abs(phase.value) * 0.5)
        .scaleEffect(phase.isIdentity ? 1.0 : 0.75)
}

onScrollGeometryChange (iOS 18+)

.onScrollGeometryChange(for: Bool.self) { geo in
    geo.contentOffset.y < geo.contentInsets.top
} action: { _, isTop in
    showBackButton = !isTop
}

onScrollVisibilityChange (iOS 18+)

VideoPlayer(player: player)
    .onScrollVisibilityChange(threshold: 0.2) { visible in
        visible ? player.play() : player.pause()
    }

Resources

WWDC: 2020-10031, 2022-10056, 2023-10148, 2024-10144, 2025-256

Docs: /swiftui/lazyvstack, /swiftui/lazyvgrid, /swiftui/lazyhgrid, /swiftui/grid, /swiftui/outlinegroup, /swiftui/disclosuregroup

Skills: axiom-swiftui-layout, axiom-swiftui-layout-ref, axiom-swiftui-nav, axiom-swiftui-26-ref

You Might Also Like

Related Skills

verify

verify

243K

Use when you want to validate changes before committing, or when you need to check all React contribution requirements.

facebook avatarfacebook
获取
test

test

243K

Use when you need to run tests for React core. Supports source, www, stable, and experimental channels.

facebook avatarfacebook
获取

Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React.

facebook avatarfacebook
获取

Use when adding new error messages to React, or seeing "unknown error code" warnings.

facebook avatarfacebook
获取
flow

flow

243K

Use when you need to run Flow type checking, or when seeing Flow type errors in React code.

facebook avatarfacebook
获取
flags

flags

243K

Use when you need to check feature flag states, compare channels, or debug why a feature behaves differently across release channels.

facebook avatarfacebook
获取