You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中List滚动位置追踪异常:PreferenceKey值重置求助

问题:List滚动位置追踪异常,向上滚动过度导致PreferenceKey值重置为0,破坏隐藏头部逻辑

我此前一直使用ScrollView追踪滚动位置,现在需要改用List实现该功能,因为要借助List的默认样式等内置特性。我通过PreferenceKeys获取滚动位置值,但向上滚动过度时,PreferenceKey的值会重置为初始的0,破坏了我的隐藏式头部(shy header)显示逻辑。

我的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) { }
}

我的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())
        }
    }
}

问题演示:

问题演示

内容的提问来源于stack exchange,提问作者Simon McNeil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:51:04