Reputation: 663
Is it possible to SET ScrollView offset in SwiftUI?
I have made a custom tab bar that uses a Switch/Case to change views. However my views all contain vertical ScrollViews. I understand that each time I switch between Views they are destroyed, and thus the scrollView offset is lost.
I have used the following approach to GET ScrollView Offset, however I am now not sure how I can use this information. I have seen there is now ScrollTo but this seems to only work with an ID.
Is it possible to use ScrollTo with an Offset in some way?
In general, what I'm trying to achieve is standard Tab bar behaviour where a user returns to the same position they left each Tab
Any help is appreciated. Also, please let me know if this is bad for performance as I am a novice. Thanks.
private struct ScrollViewOffsetPreferenceKey: PreferenceKey {
static var defaultValue: CGPoint = .zero
static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) { }
}
struct ScrollViewWithOffset<T: View>: View {
let axes: Axis.Set
let showsIndicator: Bool
let offsetChanged: (CGPoint) -> Void
let content: T
init(axes: Axis.Set = .vertical,
showsIndicator: Bool = false,
offsetChanged: @escaping (CGPoint) -> Void = { _ in },
@ViewBuilder content: () -> T
) {
self.axes = axes
self.showsIndicator = showsIndicator
self.offsetChanged = offsetChanged
self.content = content()
}
var body: some View {
ScrollView(axes, showsIndicators: showsIndicator) {
GeometryReader { proxy in
Color.clear.preference(
key: ScrollViewOffsetPreferenceKey.self,
value: proxy.frame(in: .named("scrollView")).origin
)
}
.frame(width: 0, height: 0)
content
}
.coordinateSpace(name: "scrollView")
.onPreferenceChange(ScrollViewOffsetPreferenceKey.self, perform: offsetChanged)
}
}
Used like so...
ScrollViewWithOffset { point in
scrollViewOffset = point.y
} content: {
ScrollViewReader { proxy in
LazyVStack(spacing: 4) {
ForEach(0..<10, id: \.self) { i in
Item()
.id(i)
}
}
}
}
Upvotes: 3
Views: 2084
Reputation: 3414
iOS 18 will provide a new struct ScrollPosition
.
If you target iOS 17 and earlier, you may use the offset of HStack or use an idea from Daniel Saidi which uses a GeometryReader.
Doordash has implemented a wrapper around UIScrollView to use in SwiftUI.
Upvotes: 2