0

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:

import SwiftUI

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)
                }
            }
        }
    }
}

0 Answers0