Przejdź do treści
Biblioteka skilli
Programowanie · Budowanie i kod

layout

/layout

Obejmuje układ w SwiftUI poza stosami: protokół Layout, Grid i leniwe siatki, własne kontenery, reguły wydajności LazyStack i ScrollView oraz przewijanie programowe.

Licencja
MIT
Ostatnia zmiana repozytorium
24.07.2026

Ocena i bezpieczeństwo

90/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść25 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
1
Skrypty
0
Komentarze HTML
0
Adresy URL w SKILL.md
3
Przestarzałość

Brak sygnałów. Repozytorium zmienione 24.07.2026, bez odwołań do wycofanych modeli i API.

Licencja

MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.

Co robi i kiedy

Obejmuje układ w SwiftUI poza stosami: protokół Layout, Grid i leniwe siatki, własne kontenery, reguły wydajności LazyStack i ScrollView oraz przewijanie programowe.

Oryginalny opis (EN)

SwiftUI layout beyond stacks — the Layout protocol (when custom layout beats GeometryReader), Grid vs lazy grids, custom containers with sections and container values, and lazy-stack/ScrollView performance rules (what breaks laziness, prefetch discipline, scroll APIs). Use when building custom layouts or containers, fixing lazy-stack jank or memory growth, or wiring programmatic/snapping scrolling.

Jak działa

  1. When This Skill Activates
  2. Custom Layout protocol (not GeometryReader)
  3. Grid decisions
  4. Custom containers (Demystify Containers)
  5. Lazy stacks & scrolling performance (WWDC26 rules)
  6. The scroll API map
  7. Output Format
  8. References
Sekcje z nagłówków SKILL.md, w oryginale · 111 linii, 835 słów
Podgląd SKILL.md
---
name: layout
description: SwiftUI layout beyond stacks — the Layout protocol (when custom layout beats GeometryReader), Grid vs lazy grids, custom containers with sections and container values, and lazy-stack/ScrollView performance rules (what breaks laziness, prefetch discipline, scroll APIs). Use when building custom layouts or containers, fixing lazy-stack jank or memory growth, or wiring programmatic/snapping scrolling.
allowed-tools: [Read, Write, Edit, Glob, Grep]
last_verified: 2026-07-16
review_by: 2027-06-22
---

# SwiftUI Layout & Containers

The layer between "stacks and spacers" and "it scrolls like butter with 100k rows" — Apple's
Layout protocol, container composition, and the lazy-stack rules from the WWDC26 deep dive.
View identity/data-flow questions route to `swiftui/data-flow`.

## When This Skill Activates

- "Make these buttons equal width" / measurement-dependent layout
- Building a reusable container (custom List/board/carousel) that should accept ForEach + sections
- Lazy stack jank, memory growth, scroll-position bugs, broken scroll targeting
- Programmatic scrolling, paging/snapping, scroll-linked effects
- GeometryReader causing layout loops or mangled sizing

## Custom Layout protocol (not GeometryReader)

Reach for a custom `Layout` whenever you must **measure subviews and feed the measurement back
into layout** — GeometryReader only measures its container and can't influence the engine.
Canonical case: equal-width buttons.

- `sizeThatFits`: propose `.unspecified` to read each subview's ideal size
  (`subviews.map { $0.sizeThatFits(.unspecified) }`); guard empty subviews;
  `replacingUnspecifiedDimensions()` for nil proposal dimensions.
- `placeSubviews`: never assume origin (0,0) — use `bounds.minX/midX` (non-zero origins are
  what make layouts composable); `place(at:anchor:proposal:)` with a proposal that may differ
  from the ideal size (that's how equal widths happen).
- **Respect spacing preferences**: `subviews[i].spacing.distance(to:along:)`, taking the larger
  of conflicting preferences — matching built-in containers. No hardcoded 8s.
- Per-subview data via `LayoutValueKey` (+ a `layoutValue` convenience modifier), read as
  `subview[Key.self]`.
- Cache only after Instruments shows layout cost — it's an optimization, not a requirement.
- **Switch layouts without killing identity**: `AnyLayout(HStackLayout())` ↔ custom layout with
  `.animation(_:value:)` — SwiftUI sees one changing view, so state survives and it animates.
- Don't build fallbacks into the layout — wrap alternatives in `ViewThatFits`.

## Grid decisions

| Need | Use |
|---|---|
| Static 2D with cross-row alignment | `Grid`/`GridRow` (+ `gridCellColumns` to span, `gridColumnAlignment` per column) |
| Scrollable, large content | `LazyVGrid`/`LazyHGrid` (only visible views load; one axis fixed up front) |
| "First arrangement that fits" | `ViewThatFits` |

## Custom containers (Demystify Containers)

Make containers that compose like `List` does:

- API shape: a trailing `@ViewBuilder var content: Content` — callers can then mix static
  views, `ForEach`, and conditionals.
- Iterate **resolved** children with `ForEach(subviews: content)`; need the whole collection
  (count/chunking)? `Group(subviews: content) { subviews in … }`.
- Internalize **declared vs resolved**: one declared ForEach resolves to N subviews; Group to
  its children; EmptyView to zero; `if` conditionally. Counting declared views is a bug.
- Sections are opt-in: `ForEach(sections: content)`, reading `section.header` /
  `section.content`; check `header.isEmpty` before rendering the slot.
- Per-child customization via container values: `extension ContainerValues { @Entry var … }`,
  set with a convenience modifier, read via `subview.containerValues`. Scoping model:
  **Environment flows down · Preferences flow up · container values reach only the direct
  container.** Setting one on a `Section` styles the whole section.

## Lazy stacks & scrolling performance (WWDC26 rules)

LazyVStack builds views only until the viewport fills; totals and offsets are **estimated**
from average placed-view size and corrected as you scroll. Everything below follows from that:

- **One subview per ForEach element, always.** An `if` inside a row (0-or-1 views) forces the
  stack to keep off-screen views + their `@State` alive to preserve indices — and environment
  changes then re-evaluate off-screen bodies. Filter at the data layer (`@Query` predicate);
  gate auth-type conditions *outside* the stack.
- **Never key logic off absolute scroll offset** in a lazy stack (`onScrollGeometryChange` sees
  estimates) — use `onScrollTargetVisibilityChange(threshold: 0.8)` for visibility triggers.
- **Set up in `init`, not `onAppear`** (`_model = State(initialValue:)`): body runs during
  prefetch; `onAppear` fires only on-screen, throwing prefetch work away and causing
  post-appearance size jumps. Start async loads in `init`/`task`.
- **Don't persist meaningful state in row `@State`** — off-screen views are eventually
  released. Hoist (`@State var highlighted: Set<ID>` outside, `@Binding` down).
- `scrollTransition` transforms must stay inside the original frame (scale ✅; rotations
  escaping the frame make views vanish early).
- Don't drive layout from `onGeometryChange` height feedback (content shoves, targeting
  breaks) — that's the custom `Layout` case above.
- Nest `LazyHStack` inside `LazyVStack` freely (unscrolled rows stay unloaded) — but fix child
  heights (`lineLimit`, explicit frames) in the horizontal stacks.
- `pinnedViews: [.sectionHeaders]` pins headers; infinite scroll = trailing
  `ProgressView().onAppear { fetchNextPage() }` after the ForEach.

## The scroll API map

- Snapping/paging: `scrollTargetLayout()` + `scrollTargetBehavior(.viewAligned/.paging)`.
- Track/control position: `scrollPosition` binding; programmatic `ScrollPosition` +
  `scrollTo(id:)` — works for unloaded targets *if* IDs map to stable one-subview elements.
- Scroll-linked effects: `scrollTransition` (enter/leave viewport) and `visualEffect`
  (geometry without GeometryReader) — details in `design/animation-patterns`.
- Reactions: `onScrollGeometryChange` (fine outside lazy estimation),
  `onScrollVisibilityChange` (autoplay/analytics).
- Performance floor: list/scroll internals were rewritten (WWDC25) — macOS lists ~6× faster at
  100k+ rows, and lazy loading works in nested `ScrollView`+`LazyVStack`; profile with the
  SwiftUI instrument (`performance/swiftui-debugging`).

## Output Format

Layout review: `Symptom | Rule violated | Fix` — check the one-subview-per-element rule first
in any lazy-stack complaint; it explains most jank, memory growth, and targeting bugs.

## References

- https://developer.apple.com/videos/play/wwdc2022/10056/ (Compose custom layouts)
- https://developer.apple.com/videos/play/wwdc2024/10146/ (Demystify SwiftUI containers)
- https://developer.apple.com/videos/play/wwdc2026/321/ (Dive into lazy stacks and scrolling)
- Related skills: `swiftui/data-flow` (identity/ForEach IDs), `performance/swiftui-debugging`, `design/animation-patterns` (scroll-linked effects)

Wersje

RepozytoriumWynikLicencja
Ta strona · rshankras/claude-code-apple-skills90MIT
adilkalam/orca90MIT

Migawka bazy z 13.11.2026 · wersja paczki a3790f1ad853 (skrót SHA-256 całej paczki)

Pobrania w ostatnich 30 dniach: 0 · ranking

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 90swiftui
    Zbiera wiedzę o SwiftUI: przepływ danych i Observation, layout i wydajność lazy-stacków, AlarmKit, wykresy 3D, edycja rich text, paski narzędzi i WebKit, przy błędach stanu, renderowania i przewijania.
  • 98axiom-audit-swiftui-layout
    Przegląda układy w SwiftUI pod kątem problemów z adaptacją, użyciem GeometryReader i poprawnym wyglądem na różnych urządzeniach.
  • 95swiftui-layout-components
    Buduje układy SwiftUI ze stosów, siatek, list, widoków przewijanych, formularzy i kontrolek: VStack, LazyVGrid, List z akcjami przesunięcia, ScrollViewReader i .searchable.
  • 100layout-grid
    Podaje zasady siatki i wyrównania dla aplikacji macOS w SwiftUI oraz trzy sprawdzenia, które wykrywają niewyrównane elementy.
  • 100axiom-analyze-swiftui-performance
    Analizuje wydajność SwiftUI przy zacinającym przewijaniu, wolnych animacjach i problemach z aktualizacją widoków: kosztowne body, formattery, zależności od całych kolekcji i brakujące kontenery lazy.
  • 100layout-grid
    Wyznacza zasady siatki i wyrównania dla własnych stron, kart, formularzy i arkuszy w SwiftUI na macOS, z trzema sprawdzeniami.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.