I am currently using **Xcode Version 14.3.1** (14E300c).
The scrollview in the code has an array of objects that I am iterating through with, ForEach(). When the user scrolls, lets say to object 30(each object is numbered, for demonstration purposes), with an anchor value of 0.00135(you can think of this as the offset value in relation to said object), i want the user to be able to return to the exact location prior to deinitializing the view; exactly like, pretty much, every social media application.
I have attempted to do this by using ScrollViewReader.scrollTo(<id: , anchor:), but to no avail. It works perfectly with preview, but as soon as I use the simulator or a device(iPhone 14), it starts to resize my ScrollView Content height in random sequences.
Can someone please explain why this would be working perfectly in preview but not on devices; and how can I make it work for devices without this strange bug?
So the issue happens only when you reach near the end(bottom) of the scrollable content; and oddly enough, if you scroll near the beginning(top) of the scrollable content, it fixes itself.
**// VIEW THAT IS PROBABLY CAUSING THE ISSUE**
struct ScrollViewWithSavedPosition: View {
@ObservedObject var scrollViewSavedValue: ScrollViewSavedValue
@State private var isViewLoaded: Bool = false
let geoProxy: GeometryProxy
let maxScrollableHeight: CGFloat = 4809
var body: some View {
ScrollViewReader { scrollProxy in
ScrollView(showsIndicators: false) {
LazyVStack {
ForEach(0..<34) { poster in
ZStack {
Rectangle()
.fill(.black)
.frame(width: geoProxy.size.width * 0.4,
height: geoProxy.size.height * 0.2)
Text("\(poster)")
.foregroundColor(.orange)
}
}
}
.id("scrollPosition")
.background(
GeometryReader {
Color.orange
.preference(key: CGPointPK2.self,
value: $0.frame(in: .global).origin)
}
)
.onPreferenceChange(CGPointPK2.self) { scrollPosition in
DispatchQueue.main.async {
isViewLoaded = true
}
if isViewLoaded {
let offsetValue = (-1 * (scrollPosition.y - geoProxy.safeAreaInsets.top)) / maxScrollableHeight
scrollViewSavedValue.scrollOffsetValue = offsetValue
}
print(scrollViewSavedValue.scrollOffsetValue)
}
}
.onAppear {
scrollProxy.scrollTo("scrollPosition", anchor: UnitPoint(x: 0, y: scrollViewSavedValue.scrollOffsetValue))
}
}
.preferredColorScheme(.light)
}
}
struct CGPointPK2: PreferenceKey {
static var defaultValue: CGPoint = .zero
static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) { }
}
class ScrollViewSavedValue: ObservableObject {
@Published var scrollOffsetValue: CGFloat = 0
@Published var selectedTab: Int = 1
}
struct TabBarView: View {
@ObservedObject var scrollViewSavedValue: ScrollViewSavedValue
let geoProxy: GeometryProxy
var body: some View {
VStack {
Spacer()
ZStack {
Rectangle()
.fill(.blue)
.frame(width: geoProxy.size.width, height: 80)
HStack(spacing: 100) {
Button {
DispatchQueue.main.async {
scrollViewSavedValue.selectedTab = 1
}
} label: {
ZStack {
Circle()
.fill(.black)
.frame(width: 60, height: 60)
Text("View 1")
.foregroundColor(.white)
.font(.system(size: 12))
.fontWeight(.bold)
}
}
Button {
DispatchQueue.main.async {
scrollViewSavedValue.selectedTab = 2
}
} label: {
ZStack {
Circle()
.fill(.black)
.frame(width: 60, height: 60)
Text("View 2")
.foregroundColor(.white)
.font(.system(size: 12))
.fontWeight(.bold)
}
}
}
}
}
.ignoresSafeArea()
}
}
struct PresentationView: View {
@StateObject private var scrollViewSavedValue = ScrollViewSavedValue()
var body: some View {
GeometryReader { geoProxy in
switch scrollViewSavedValue.selectedTab {
case 1:
ScrollViewWithSavedPosition(scrollViewSavedValue: scrollViewSavedValue, geoProxy: geoProxy)
default:
Text("View 2")
.foregroundColor(.black)
}
TabBarView(scrollViewSavedValue: scrollViewSavedValue, geoProxy: geoProxy)
}
}
}