Stacks, Grids, and Outlines in SwiftUI
Stacks
New lazy stack views: LazyVStack
and LazyHStack
They work just like the existing horizontal and vertical stacks, but they render their content incrementally as it becomes visible
Useful for very long lists built using VStack/HStack
that had performance issues previously
There’s no point using lazy stacks for small local stacks that just lay out single views that are all visible on the screen together
If you’re unsure, use standard HStack/VStack
by default, and only use lazy stacks for long content that’s scrolling and becomes a performance bottleneck
Grids
New grid views: LazyHGrid
and LazyVGrid
They lay out subviews in a grid like collection view
LazyVGrid(columns: columns, spacing: 0) { … }
Grids require a definition of columns:
Constant number of columns:
var columns = [ GridItem(spacing: 0), GridItem(spacing: 0), GridItem(spacing: 0) ]
Adaptive columns, number depends on the window size:
var columns = [ GridItem(.adaptive(minimum: 300), spacing: 0) ]
Lists and outlines
Lists are more than just stacks of content – they support selection and scrolling etc.
Lists don’t need a Lazy variant, because list contents are always loaded lazily
Lists can now show hierarchical trees of items (outlines)
To make an outline list, provide a “children” keypath:
List(graphics, children: \.children) { graphic in GraphicRow(graphic) }
To make collapsible list sections, use an OutlineGroup
:
ForEach(canvases) { canvas in Section(header: Text(canvas.name)) { OutlineGroup(items, children: \.children) { graphic in GraphicRow(graphic) } } }
You can also implement other views with parts that the user can collapse and expand like in an outline using DisclosureGroup
:
DisclosureGroup(isExpanded: $expanded) { Contents() } label: { Label(“Name”) }
or:
DisclosureGroup(“Label”) { contents }