I have a problem with the SwiftUI component in the beta version of iOS 17. In iOS 16, the "parallaxedView" element would stretch its height when scrolling to the top of the screen, and upon releasing the finger, the height would return to its original value. In version 17, it doesn't seem to be working. The "scrollOffset" value attempts to be set, but quickly returns to 0, which prevents the container's height from changing. What could be the issue?
Here's the simplified component code:
private struct ScrollOffsetPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = .zero
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {}
}
struct ParallaxView<ParallaxedView: View, ContentView: View>: View {
private let parallaxedView: () -> ParallaxedView
private let contentView: (_ containerHeight: CGFloat) -> ContentView
private let navBarHeight: CGFloat = 80
private let maxParallaxedViewHeight: CGFloat = 390
private let buttonSize: CGFloat = 50
@State var scrollOffset: CGFloat = 0
@State var cachedLastOffset: CGFloat = 0
@State private var containerHeight: CGFloat = 0
private var parallaxedViewHeight: CGFloat {
min(UIScreen.main.bounds.size.width, maxParallaxedViewHeight)
}
@inlinable
public init(
@ViewBuilder
parallaxedView: @escaping () -> ParallaxedView,
@ViewBuilder
contentView: @escaping (_ containerHeight: CGFloat) -> ContentView
) {
self.parallaxedView = parallaxedView
self.contentView = contentView
}
var body: some View {
GeometryReader { geometry in
let inset = geometry.safeAreaInsets.top
let shadowOffset = max(0, min(1, ((scrollOffset) / (parallaxedViewHeight - (inset + navBarHeight)))))
ZStack(alignment: .topTrailing) {
ScrollView {
ZStack(alignment: .topTrailing) {
VStack(spacing: 0) {
GeometryReader { geometry in
let scrollOffsetInner = -geometry.frame(in: .named("scroll")).minY
Color.clear
.preference(
key: ScrollOffsetPreferenceKey.self,
value: scrollOffsetInner
)
}
.frame(height: 0)
.onPreferenceChange(ScrollOffsetPreferenceKey.self, perform: { offset in
self.scrollOffset = CGFloat(offset)
})
parallaxedView()
.frame(height: parallaxedViewHeight + max(-scrollOffset, 0))
.offset(y: scrollOffset / (scrollOffset > 0 ? 2 : 1))
contentView(self.containerHeight)
.background(Color("Background"))
.offset(y: -max(-scrollOffset, 0))
}
GeometryReader { geometry in
Color.clear
.onChange(of: geometry.frame(in: .named("scroll")).minY, initial: true) { _, _ in
self.containerHeight = geometry.size.height
}
.onAppear {
self.containerHeight = geometry.size.height
}
.frame(minHeight: 0, maxHeight: .infinity)
.frame(width: 10)
.zIndex(10)
}
}
.padding(.bottom, 15)
}
.edgesIgnoringSafeArea(SwiftUI.Edge.Set.top)
GeometryReader { geometry in
VStack(spacing: 0) {
Color("Background")
.frame(height: geometry.safeAreaInsets.top + navBarHeight - 5)
Color("Background")
.frame(height: 5)
.shadow(color: Color("Black").opacity(0.15), radius: 2, x: 0, y: 4)
}
.offset(y: -geometry.safeAreaInsets.top)
.opacity(shadowOffset)
}
}
}
}
}