PinnedScrollView
PinnedScrollView is a tiny SwiftUI library that helps you pin any view in a scrollview like a header, without using LazyVStack
and Section
.
Usage
var body: some View {
ScrollView {
VStack(spacing: 0) {
ForEach(0..<20) { _ in
Text("Header")
.pinned() // 1
Text("Some content text")
}
}
}
.pinnedScrollView() // 2
}
- Add
.pinned()
modifier to the view you want to pin within the scrollview - Add
.pinnedScrollView()
modifier to the corresponding scrollview
That’s it!
Optional observation
You can also provide a optional closure onReachedTop: (Bool) -> ()
to the pinned
modifier if you want to get a notification when the pinned state changed.
@State private var isHeaderReachedTop = false
// ...
Text("Header" + (isHeaderReachedTop ? " Reached" : ""))
.pinned { isReachedTop in
isHeaderReachedTop = isReachedTop
}
Limitation
PinnedScrollView requires iOS/iPadOS 14.0.
PinnedScrollView only supports vertical ScrollView
and doesn’t support horizontal ScrollView
or the List
view.
Installation
Use Swift Package Manager to add PinnedScrollView to your project.
https://github.com/Lumisilk/PinnedScrollView.git
License
This package is licensed under the MIT open-source license.
Inspiration
The implementation of PinnedScrollView was inspired by objc.io’s course on Sticky Headers for Scroll Views.
Unlike the original implementation from objc.io, which uses PreferenceKey
to coordinate the frames of headers and can lead to performance bottlenecks, PinnedScrollView use onChange
to efficiently record the frames of headers.
Additionally, PinnedScrollView use Combine’s debounce
and publisher to minimize the re-evaluation count of the headers’ body, aiming to optimize performance.
Special thanks to @auramagi for the algorithm suggestions.