axiom-swiftui-containers-ref について
axiom-swiftui-containers-refは、iOS 14からiOS 26までのコンテナを扱うSwiftUI開発者向けリファレンススキルです。スタック、グリッド、階層表示、スクロール、性能の指針を用途別に解説します。
主な機能
- 01スタック・グリッド・階層コンテナの選択
- 02遅延読み込みスクロールリストの構築
- 03グリッドとカルーセルの作成
- 04展開可能な階層データの表示
- 05スクロール位置とトランジションの活用
- 06コンテナの性能に関する指針
活用シーン
- 01大量の項目を扱うスクロールリストの構築
- 02レスポンシブな写真グリッドの作成
- 03ファイルツリーや展開可能な設定の表示
- 04横スクロールコンテンツへのスナップ追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-swiftui-containers-refインストール後、Claude Code で/axiom-swiftui-containers-refを入力して読み込まれたか確認します。
詳細
SwiftUI コンテナリファレンス
スタック、グリッド、アウトライン、スクロール機能の強化。iOS 14 から iOS 26 まで。
ソース:WWDC 2020-10031、2022-10056、2023-10148、2024-10144、2025-256
クイック選択ガイド
| ユースケース | コンテナ | iOS |
|---|---|---|
| 固定ビューを縦または横に配置 | VStack / HStack | 13+ |
| ビューを重ねて配置 | ZStack | 13+ |
| 大きなスクロール可能リスト | LazyVStack / LazyHStack | 14+ |
| 複数列のグリッド | LazyVGrid | 14+ |
| 複数行のグリッド(横方向) | LazyHGrid | 14+ |
| 静的グリッド、正確な位置合わせ | Grid | 16+ |
| 階層データ(ツリー) | children: を指定した List | 14+ |
| カスタム階層 | OutlineGroup | 14+ |
| コンテンツの表示/非表示 | DisclosureGroup | 14+ |
パート 1:スタック
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 の配置:.center(デフォルト)、.top、.bottom、.leading、.trailing、.topLeading、.topTrailing、.bottomLeading、.bottomTrailing
Spacer
HStack {
Text("Left")
Spacer()
Text("Right")
}
Spacer(minLength: 20) // Minimum size
LazyVStack、LazyHStack(iOS 14+)
表示されているときにのみ子ビューを描画します。ScrollView 内で使用します。
ScrollView {
LazyVStack(spacing: 0) {
ForEach(items) { item in
ItemRow(item: item)
}
}
}
固定セクションヘッダー
ScrollView {
LazyVStack(pinnedViews: [.sectionHeaders]) {
ForEach(sections) { section in
Section(header: SectionHeader(section)) {
ForEach(section.items) { item in
ItemRow(item: item)
}
}
}
}
}
パート 2:グリッド
Grid(iOS 16+)
正確な位置合わせが可能な非遅延読み込みのグリッドです。すべてのビューを一度に読み込みます。
Grid(alignment: .leading, horizontalSpacing: 10, verticalSpacing: 10) {
GridRow {
Text("Name")
TextField("Enter name", text: $name)
}
GridRow {
Text("Email")
TextField("Enter email", text: $email)
}
}
モディファイア:
gridCellColumns(_:)— 複数の列にまたがりますgridColumnAlignment(_:)— 列の配置を上書きします
Grid {
GridRow {
Text("Header").gridCellColumns(2)
}
GridRow {
Text("Left")
Text("Right").gridColumnAlignment(.trailing)
}
}
LazyVGrid(iOS 14+)
縦スクロールのグリッドです。列を定義し、行数は制限なく増やせます。
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
ScrollView {
LazyVGrid(columns: columns, spacing: 16) {
ForEach(items) { item in
ItemCard(item: item)
}
}
}
LazyHGrid(iOS 14+)
横スクロールのグリッドです。行を定義し、列数は制限なく増やせます。
let rows = [GridItem(.fixed(100)), GridItem(.fixed(100))]
ScrollView(.horizontal) {
LazyHGrid(rows: rows, spacing: 16) {
ForEach(items) { item in
ItemCard(item: item)
}
}
}
GridItem.Size
| サイズ | 動作 |
|---|---|
.fixed(CGFloat) | 幅/高さを正確に指定します |
.flexible(minimum:maximum:) | 空間を均等に埋めます |
.adaptive(minimum:maximum:) | 収まる数だけ作成します |
// Adaptive: responsive column count
let columns = [GridItem(.adaptive(minimum: 150))]
パート 3:アウトライン
階層データを含む List(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+)
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)
}
パート 4:よく使われるパターン
写真グリッド
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()
}
}
}
横方向のカルーセル
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack(spacing: 16) {
ForEach(items) { item in
CarouselCard(item: item).frame(width: 280)
}
}
.padding(.horizontal)
}
ファイルブラウザー
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)
パート 5:パフォーマンス
遅延読み込みを使用する場合
| サイズ | スクロール可能か | 使用するもの |
|---|---|---|
| 1-20 | いいえ | VStack/HStack |
| 1-20 | はい | ScrollView 内の VStack/HStack |
| 20-100 | はい | LazyVStack/LazyHStack |
| 100+ | はい | LazyVStack/LazyHStack または List |
| グリッド <50 | いいえ | Grid |
| グリッド 50+ | はい | LazyVGrid/LazyHGrid |
GridItem 配列をキャッシュする — body の外で定義します:
struct ContentView: View {
let columns = [GridItem(.adaptive(minimum: 150))] // ✅
var body: some View {
LazyVGrid(columns: columns) { ... }
}
}
iOS 26 のパフォーマンス
- 10 万件以上のアイテムでリスト読み込みが 6 倍高速
- リスト更新が 16 倍高速
- スクロール時のフレーム落ちを軽減
- 遅延スタックを使ったネストされた ScrollView で、読み込みが適切に遅延されるようになりました:
ScrollView(.horizontal) {
LazyHStack {
ForEach(photoSets) { set in
ScrollView(.vertical) {
LazyVStack {
ForEach(set.photos) { PhotoView(photo: $0) }
}
}
}
}
}
パート 6:スクロール機能の強化
containerRelativeFrame(iOS 17+)
スクロールコンテナを基準にビューのサイズを設定します。
ScrollView(.horizontal) {
LazyHStack {
ForEach(cards) { card in
CardView(card: card)
.containerRelativeFrame(.horizontal, count: 3, span: 1, spacing: 16)
}
}
}
scrollTargetLayout(iOS 17+)
スナップを有効にします。
ScrollView(.horizontal) {
LazyHStack {
ForEach(items) { ItemCard(item: $0) }
}
.scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)
scrollPosition(iOS 17+)
最上部に表示されているアイテムを追跡します。各アイテムに .id() が必要です。
@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()
}
リソース
WWDC:2020-10031、2022-10056、2023-10148、2024-10144、2025-256
ドキュメント:/swiftui/lazyvstack、/swiftui/lazyvgrid、/swiftui/lazyhgrid、/swiftui/grid、/swiftui/outlinegroup、/swiftui/disclosuregroup
スキル:axiom-swiftui-layout、axiom-swiftui-layout-ref、axiom-swiftui-nav、axiom-swiftui-26-ref