SwiftUI: Layout & Interfaces

Nov 18 2021 Swift 5.5, iOS 15, Xcode 13

Part 1: Dynamic View Layout

6. PinnedScrollableViews

Episode complete

Play next episode

Save for later
About this episode
See versions

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 5. Grids Next episode: 7. Challenge: Grids with Pinned Views

Update Notes: This course was originally recorded in 2020. It has been reviewed and all content and materials updated as of October 2021.

In this course, you’ve been working with sections of views. But you haven’t used SwiftUI’s Section View. In this episode, that will change! Sections are used for adding headers and footers to views, and there are a couple of associated options available to you. Let’s check ’em out.

Here, we have a LazyVStack with 5 subgenre views, for each genre.

But unless you’re really up on your musical genres, there’s no visual indication of where one genre ends, and another begins. A Section allows us to add, as one option, a header, to a view.

        ForEach(Genre.list) { genre in
          Section(header: )
          ForEach(genre.subgenres.prefix(5)) {

And in this Starter project, I’ve added a Genre Header view type, below, to test that out.

        ForEach(Genre.list) { genre in
          Section(header: genre.header) {
            ForEach(genre.subgenres.prefix(5)) {
              $0.view.frame(width: 125)

Now, as we scroll through, we know what genre we’re looking at. You can use any view you want, for this. The reason that I’ve made a blurring header view for you to try, is that you can pin the headers.

You do that by adding an argument to either a Stack, or a grid. Its label is “pinnedViews”.

LazyVStack(pinnedViews: /*@START_MENU_TOKEN@*/[]/*@END_MENU_TOKEN@*/) {

The type of this argument is a “PinnedScrollableViews”. It’s an option set, and you’ve got two options available. One is Section Headers.

LazyVStack(pinnedViews: .sectionHeaders) {

Now, as you scroll through, a header will stick around onscreen, as long as its section is visible. And you see the blurred views pass “below” the headers.

Unfortunately, there’s no way to do that in pure SwiftUI yet, but the code for it is in this project if you want to learn how it’s done.

Now, let’s add a footer to the sections, to see the difference, live, between pinning, and not pinning. (You can just use the “header” as a footer view, for a demonstration.)

            header: genre.header,
            footer: genre.header
          ) {

The headers are always visible for a section, but you have to scroll down to the bottom of a section, to see the footers. You can change that, by pinning the footers too.

LazyVStack(pinnedViews: [.sectionHeaders, .sectionFooters]) {

It’s very unlikely that you’d ever want the same view for both a header, and a footer, but now, you’re familiar with all of the available options. …that is, for VStacks. For HStacks…

LazyHStack(pinnedViews: [.sectionHeaders, .sectionFooters]) {

…just switch the scroll direction, as per usual.

ScrollView(.horizontal) {

The naming isn’t really accurate anymore. I don’t think of something on the left as a “header” or something on the right, as a footer, but as least they do what you might expect: the same idea, in a different axis. And as I mentioned, headers and footers, pinned or not, work with grids, also.


Just provide the rows or columns you need.

        pinnedViews: [.sectionHeaders, .sectionFooters]
      ) {

…like, for example, an array of 6 flexible grid items.

rows: .init(repeating: .init(), count: 6),

We can see the result better, by getting rid of the prefix, now.

ForEach(genre.subgenres) {

And that’s all for headers and footers. You’ll get more practice using them with grids in the next episode!