Blog

SwiftUI Alignment Guides

In the fourth of our Thinking in SwiftUI challenges, we asked you to align two columns, without using preferences:

We start with this code:

VStack {
    HStack {
        Text("100 m").font(Font.body.bold())
        Text("Usain Bolt")
    }
    HStack {
        Text("5 km").font(Font.body.bold())
        Text("Joshua Cheptegei")
    }
    HStack {
        Text("10 km").font(Font.body.bold())
        Text("Rhonex Kipruto")
    }
    HStack {
        Text("Marathon").font(Font.body.bold())
        Text("Eliud Kipchoge")
    }
}

We can solve this challenge by using alignment guides, a technique we discovered in an article by Scott James Remnant.

First, we create a custom horizontal alignment, and apply it to the second label of each HStack. Then we use that same alignment on the outer VStack to make sure that all the names of the record holders are aligned at the leading edge.

Here’s our custom alignment ID:

struct CustomAlignment: AlignmentID {
    static func defaultValue(in context: ViewDimensions) -> CGFloat {
        return context[.leading]
    }
}

extension HorizontalAlignment {
    static let custom: HorizontalAlignment = HorizontalAlignment(CustomAlignment.self)
}

We can modify the VStack of HStacks like so:

VStack(alignment: .custom) {
    HStack {
        Text("100 m").font(Font.body.bold())
        Text("Usain Bolt").alignmentGuide(.custom) { $0[.leading] }
    }
    HStack {
        Text("5 km").font(Font.body.bold())
        Text("Joshua Cheptegei").alignmentGuide(.custom) { $0[.leading] }
    }
    HStack {
        Text("10 km").font(Font.body.bold())
        Text("Rhonex Kipruto").alignmentGuide(.custom) { $0[.leading] }
    }
    HStack {
        Text("Half Marathon").font(Font.body.bold())
        Text("Geoffrey Kamworor").alignmentGuide(.custom) { $0[.leading] }
    }
}

Clearly, the code has far too much duplication, and could be made simpler using a few abstractions. However, there is a more serious limitation: while alignment guides are a simple solution to this problem, they only help in some cases.

For example, with this technique we can’t create a two-column layout in which both columns are left-aligned: the outer VStack can only align its children along one alignment guide, whereas we would need two guides (one per column) for two left-aligned columns.

In our new book, Thinking in SwiftUI, we discuss the layout system in more detail. In chapter 5, as an exercise we build a multi-column table. The solution is more complicated, but works in many more cases:

At the time of writing, five out of six chapters have been released, and the final chapter, on animations, will be released next week!

You can join the early access here.


Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts