Here's a sample code:
struct PinnedHeaderView: View {
@State private var topSafeAreaPadding = CGFloat.zero
@State private var edges: Edge.Set = [.top]
private let scrollSpaceName = "CustomScrollViewSpace"
var body: some View {
GeometryReader { proxy in
ScrollView {
LazyVStack(alignment: .leading, spacing: 0, pinnedViews: .sectionHeaders) {
Section {
Color.red
.frame(height: 800)
}
Section {
Color.blue
.frame(height: 800)
} header: {
Color.green
.frame(height: 100)
.coordinateSpace(name: scrollSpaceName)
.background {
GeometryReader { proxy in
Color.clear
.onChange(of: proxy.frame(in: .named(scrollSpaceName))) { oldValue, newValue in
let threshold = 100 + newValue.origin.y - topSafeAreaPadding
self.edges = threshold <= 0 ? [] : [.top]
}
}
}
}
}
}
.ignoresSafeArea(edges: edges)
.onGeometryChange(for: CGFloat.self, of: \.safeAreaInsets.top) { newValue in
self.topSafeAreaPadding = newValue
}
}
}
}
And here's the code from scene(_:willConnectTo:options:):
guard let scene = (scene as? UIWindowScene) else { return }
window = Window(windowScene: scene)
let view = PinnedHeaderView()
let viewController = UIHostingController(rootView: view)
let navigationController = UINavigationController(rootViewController: viewController)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()