Created
July 20, 2021 20:28
-
-
Save insidegui/8dfac0b52a70bb4c4513934672d3093c to your computer and use it in GitHub Desktop.
A SwiftUI ViewModifier that can be used to read a ScrollView's offset and store it into a @State property of the view
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct ScrollViewOffsetPreferenceKey: PreferenceKey { | |
static var defaultValue: CGPoint = .zero | |
static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) { | |
value = nextValue() | |
print("value = \(value)") | |
} | |
typealias Value = CGPoint | |
} | |
struct ScrollViewOffsetModifier: ViewModifier { | |
let coordinateSpace: String | |
@Binding var offset: CGPoint | |
func body(content: Content) -> some View { | |
ZStack { | |
content | |
GeometryReader { proxy in | |
let x = proxy.frame(in: .named(coordinateSpace)).minX | |
let y = proxy.frame(in: .named(coordinateSpace)).minY | |
Color.clear.preference(key: ScrollViewOffsetPreferenceKey.self, value: CGPoint(x: x * -1, y: y * -1)) | |
} | |
} | |
.onPreferenceChange(ScrollViewOffsetPreferenceKey.self) { value in | |
offset = value | |
} | |
} | |
} | |
extension View { | |
func readingScrollView(from coordinateSpace: String, into binding: Binding<CGPoint>) -> some View { | |
modifier(ScrollViewOffsetModifier(coordinateSpace: coordinateSpace, offset: binding)) | |
} | |
} | |
// Sample usage: | |
struct CarouselView: View { | |
let items = (0..<10).map({ $0 }) | |
@State var offset: CGPoint = .zero | |
var body: some View { | |
VStack { | |
Text("Offset: \(offset.x)") | |
ScrollView(.horizontal, showsIndicators: false) { | |
LazyHStack(spacing: 16) { | |
ForEach(items, id: \.self) { _ in | |
RoundedRectangle(cornerRadius: 12, style: .continuous) | |
.frame(width: 90, height: 90) | |
.foregroundColor(.blue) | |
} | |
} | |
.readingScrollView(from: "scroll", into: $offset) | |
} | |
.coordinateSpace(name: "scroll") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment