import SwiftUI struct ScrollViewOffsetPreferenceKey: PreferenceKey { typealias Value = CGFloat static var defaultValue = CGFloat.zero static func reduce(value: inout Value, nextValue: () -> Value) { value += nextValue() } } struct ObservableScrollView: View where Content: View { @Namespace var scrollSpace @Binding var scrollOffset: CGFloat let content: () -> Content init( scrollOffset: Binding, @ViewBuilder content: @escaping () -> Content ) { _scrollOffset = scrollOffset self.content = content } var body: some View { ScrollView { content() .background( GeometryReader { geo in let offset = -geo.frame(in: .named(scrollSpace)).minY Color.clear .preference( key: ScrollViewOffsetPreferenceKey.self, value: offset) }) } .coordinateSpace(name: scrollSpace) .onPreferenceChange(ScrollViewOffsetPreferenceKey.self) { value in scrollOffset = value } } }