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

ScrollViewReader首次点击无法锚定顶部滚动到指定ID的问题

问题原因及修复方案

问题原因

  1. 代理存储时机偏差:你用@State private var scrollProxy: ScrollViewProxy?存储滚动代理的方式存在问题,List.onAppear的触发晚于页面加载完成时间,首次点击按钮时scrollProxy可能还未绑定到有效代理实例,或代理状态未完全就绪。
  2. List懒加载导致布局计算异常:List是懒加载容器,首次滚动到ID为990的单元格时,该单元格尚未完成渲染,此时scrollTo的.top锚点无法基于稳定的单元格布局计算,导致滚动位置不符合预期;第二次点击时单元格已渲染完成,布局参数稳定,锚点设置就能正常生效。

修复方案

方案一:直接使用ScrollViewReader内置代理(推荐)

移除额外的scrollProxy变量,直接在ScrollViewReader闭包内实现滚动逻辑,确保始终使用实时有效的代理实例,配合动画让滚动行为更稳定:

struct ContentView: View {
    var body: some View {
        NavigationStack {
            ScrollViewReader { proxy in
                List(0..<1000, id: \.self) { index in
                    VStack(alignment: .leading) {
                        Text("cell \(index)")
                            .font(.title)
                        Text("text 1")
                            .font(.subheadline)
                        Text("text 2")
                            .font(.subheadline)
                    }
                }
                .toolbar {
                    ToolbarItem {
                        Button("Go to 990") {
                            withAnimation {
                                proxy.scrollTo(990, anchor: .top)
                            }
                        }
                    }
                }
            }
        }
        #if os(macOS)
        .frame(minWidth: 500, minHeight: 300)
        #endif
    }
}

方案二:延迟执行滚动(适配懒加载布局)

如果要保留原有代码结构,可通过DispatchQueue.main.async延迟执行滚动操作,给单元格足够的渲染时间,确保布局稳定后再计算锚点位置:

struct ContentView: View {
    
    @State private var scrollProxy: ScrollViewProxy?
    
    var body: some View {
        NavigationStack {
            ScrollViewReader { proxy in
                List(0..<1000, id: \.self) { index in
                    VStack(alignment: .leading) {
                        Text("cell \(index)")
                            .font(.title)
                        Text("text 1")
                            .font(.subheadline)
                        Text("text 2")
                            .font(.subheadline)
                    }
                }
                .onAppear {
                    scrollProxy = proxy
                }
            }
            .toolbar {
                ToolbarItem {
                    Button("Go to 990") {
                        DispatchQueue.main.async {
                            scrollProxy?.scrollTo(990, anchor: .top)
                        }
                    }
                }
            }
        }
        #if os(macOS)
        .frame(minWidth: 500, minHeight: 300)
        #endif
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:05:17