Jun 24, 2020

Use PinnedScrollableViews to make sticky headers

So today is WWDC-20 day 3 and already a ton of useful APIs added in SwiftUI. The biggest in my opinion being new App protocol (A type that represents the structure and behavior of an app.) This enabled pure SwiftUI App without need of importing UIKit. Apple also introduced many SwiftUI replacement Views for traditional UIKit Views. Availability of newly introduced APIs like Lazy Grids, ScrollViewReader, MapView, ProgressView etc which allows users to be less dependent on UIKit.


This is big as I guess it is the beginning of very gradual UIKit deprecation and goes with strategy of Apple unifying all platforms. They want UX consistency across iPadOS, iOS, WatchOS, tvOS and macOS and without a common set of developer tools it is not feasible. I think SwiftUI is part of that game.


Anyway let's see today how in SwiftUI we can implement sticky headers inside a scrollview using a newly introduced type called PinnedScrollableViews.


struct StickyHeaderViewExample: View {

    var stickyHeaderView: some View {
        RoundedRectangle(cornerRadius: 25.0, style: .continuous)
            .fill(Color.gray)
            .frame(maxWidth: .infinity)
            .frame(height: 64)
            .overlay(
                Text("Section")
                    .foregroundColor(Color.white)
                    .font(.largeTitle)
            )
    }
    var body: some View {
        NavigationView {
            ScrollView {
                LazyVStack(alignment: .center, spacing: 40, pinnedViews: [.sectionHeaders], content: {
                    ForEach(0...50, id: \.self) { count in
                        Section(header: stickyHeaderView) {
                            MyCell()
                        }
                    }
                })
            }
        }
    }
}

struct MyCell: View {
    var body: some View {
        VStack {
            Rectangle()
                .fill(Color.red)
                .frame(width: 100, height: 100)
            HStack {
                Image(systemName: "heart")
                Text("WWDC 20")
                    .foregroundColor(.blue)
                    .font(.headline)
            }
            Text("PinnedScrollableViews")
                .foregroundColor(.blue)
                .font(.subheadline)
        }
    }
}

The main point above in the code is pinnedViews: [.sectionHeaders] which is passed in the initializer of LazyVStack

It is also possible to make sticky footer by passing sectionFooters like [.sectionHeaders, .sectionFooters]


Here is how it looks

PinnedScrollableViews

Enjoy WWDC20

Tagged with: