Stacks, Grids, and Outlines in SwiftUI

Description: Display detailed data in your SwiftUI apps more quickly and efficiently with improved stacks and new list and outline views. Now available on iOS and iPadOS for the first time, outlines are a new multi-platform tool for expressing hierarchical data that work alongside stacks and lists. Learn how to use new and improved tools in SwiftUI to display more content on screen when using table views, create smooth-scrolling and responsive stacks, and build out list views for content that needs more than a vStack can provide. Take your layout options even further with the new grid view, as well as disclosure groups. To get the most out of this video, we recommend first checking out “SwiftUI App Essentials,” which provides an overview of everything new in SwiftUI for 2020. If you’re brand-new to coding with SwiftUI, we also suggest watching 2019’s “SwiftUI Essentials” talk.

Stacks

When working with stacks of many elements embedded in ScrollViews, instead of loading everything immediately with HStack/VStack, we can now use LazyHStack and LazyVStack, which load their children lazily.

Not all stacks should be lazy, for example overlays and backgrounds are views that will be drawn only when it's time to be displayed, therefore using lazy stacks don't bring any benefit in these cases.

Grids

SwiftUI Grids are the equivalent of css's Flexbox layout.

LazyVGrid and LazyHGrid, similar to stacks, but for multi-column layouts.

When working with grids, we define our columns/rows layout via an array of GridItem instances.
Each item will specify how its relative column width/row height is computed.

GridItems are flexible by default, therefore taking all the space available:

// Creates a three column layout, with equally distributed space between the three columns.

var columns = [
    GridItem(spacing: 0),
    GridItem(spacing: 0),
    GridItem(spacing: 0)
]

ScrollView {
    LazyVGrid(columns: columns, spacing: 0) {
        ForEach(...) { ... in
           ...
        }
    }
}

We can also create an adaptive grid layout by declaring

// Creates as many columns as possible, each with a minimum width of 300 points.

var columns = [
    GridItem(.adaptive(minimum: 300), spacing: 0)
]

ScrollView {
    LazyVGrid(columns: columns, spacing: 0) {
        ForEach(...) { ... in
           ...
        }
    }
}

Progressive Display of Information

Disclosure Groups

DisclosureGroup is a new SwiftUI element that shows/hides content to the user based on a boolean @Binding.

DisclosureGroup(isExpanded: $showingContent) {
   // content here
} label: {
   Text("Show content")
}

It can be seen as a more adaptive version of the following code:

Button { 
   showingContent.toggle() 
} label: {
   Text("Show content")
}

if showingContent {
   // content here
}

Passing a binding is optional:
if we don't provide one, the view will use an internal binding and start with isExpanded set to false.

Outlines

An OutlineGroup is similar to a ForEach except that, instead of iterating over a flat collection, OutlineGroup traverses a tree structure data.

For example, this view can be used to display and explore a folder structure or a binary tree.

OutlineGroup(
    array,
    children: \.children
) { element in
    ...
}

OutlineGroup needs to know how to traverse our model, therefore it has a few requirements:

  1. we must pass a collection of Identifiable objects
  2. these objects need to have a property, passed via \.children keypath in the example above, that contain an optional collection of the same type

By default the user:

  • will only see the elements of the top "level" of the structure at first
  • will be able to tap on those elements that contain "sub-collections" to display them.

Behind the scenes OutlineGroup uses DisclosureGroup to show/hide the nested elements.

OutlineGroup is not eager: it computes its rows on demand, based on what it needs to display.

Lists

List has also gained the same capabilities of OutlineGroup.

Missing anything? Corrections? Contributions are welcome 😃

Related

Written by

Federico Zanetello

Federico Zanetello

Software engineer with a strong passion for well-written code, thought-out composable architectures, automation, tests, and more.