跟踪列表 SwiftUI 中的滚动位置

Sim*_*eil 5 xcode list swiftui

因此,过去我一直使用滚动视图跟踪滚动位置,但我陷入了需要使用列表跟踪位置的情况。我使用列表是因为我想要一些内置的空间来创建我的视图,例如默认的列表样式。

我可以使用 PreferenceKeys 获取该值,但问题是当我向上滚动到远处时,PreferenceKey 值将默认返回到其位置 0,从而破坏了我的 show shy 标题视图逻辑。

这是TrackableListView代码

struct TrackableListView<Content: View>: View {
    let offsetChanged: (CGPoint) -> Void
    let content: Content
    
    init(offsetChanged: @escaping (CGPoint) -> Void = { _ in }, @ViewBuilder content: () -> Content) {
        self.offsetChanged = offsetChanged
        self.content = content()
    }
    
    var body: some View {
        List {
            GeometryReader { geometry in
                Color.clear.preference(key: ScrollOffsetPreferenceKey.self, value: geometry.frame(in: .named("ListView")).origin)
            }
            .frame(width: 0, height: 0)
            content
                .offset(y: -10)
        }
        .coordinateSpace(name: "ListView")
        .onPreferenceChange(ScrollOffsetPreferenceKey.self, perform: offsetChanged)
    }
}

private struct ScrollOffsetPreferenceKey: PreferenceKey {
    static var defaultValue: CGPoint = .zero
    static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) { }
}
Run Code Online (Sandbox Code Playgroud)

这是我的ContentView

struct ContentView: View {
    @State private var contentOffset = CGFloat(0)
    @State private var offsetPositionValue: CGFloat = 0
    
    @State private var isShyHeaderVisible = false
    
    var body: some View {
        NavigationView {
            ZStack {
                TrackableListView { offset in
                    withAnimation {
                        contentOffset = offset.y
                    }
                } content: {
                    Text("\(contentOffset)")
                }
                .overlay(
                    ZStack {
                        HStack {
                            Text("Total points")
                                .foregroundColor(.white)
                                .lineLimit(1)
                            
                            Spacer()
                            
                            Text("20,000 pts")
                                .foregroundColor(.white)
                                .padding(.leading, 50)
                        }
                        .padding(.horizontal)
                        .padding(.vertical, 8)
                        .frame(width: UIScreen.main.bounds.width)
                        .background(Color.green)
                        .offset(y: contentOffset < 50 ? 0 : -5)
                        .opacity(contentOffset < 50 ? 1 : 0)
                        .transition(.move(edge: .top))
                    }
                    .frame(maxHeight: .infinity, alignment: .top)
                )
            }
            .navigationTitle("Hello")
            .navigationViewStyle(StackNavigationViewStyle())
            .navigationBarTitleDisplayMode(.inline)
            .frame(maxHeight: .infinity, alignment: .top)
            .background(AccountBackground())
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Sim*_*eil 4

问题是我的层次结构中的其他视图(可能由 SwiftUI 引入)可能会发送默认值,这就是为什么有时你会开始得到零。

我需要的是一种方法来确定何时使用或转发新值,以及何时忽略它。

为此,我必须将我的值设置为可选 GCPoint,默认值为零,然后在使用 PreferenceKeys 时在您的reduce方法中执行以下操作:

if let nextValue = nextValue() {
    value = nextValue 
}
Run Code Online (Sandbox Code Playgroud)

然后确保您的 CGPoint 是可选值。