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

ScrollViewProxy的scrollTo()在列表滚动时失效,如何解决?

解决SwiftUI列表减速滚动时scrollTo()失效的问题

当List处于减速滚动状态时,调用scrollTo()方法不会立即生效,必须等滚动完全停止后才能触发,这个问题在iOS 17真机上必现,模拟器偶现。要解决这个问题,我们可以借助UIKit的UIScrollView API强制停止滚动,再执行滚动到顶部的操作。

具体实现步骤

  1. 实现一个UIViewRepresentable组件,用来获取List底层的UIScrollView并控制其滚动状态
  2. 在视图中添加状态变量,触发停止滚动的操作
  3. 点击按钮时,先停止滚动,再调用scrollTo()

修改后的完整代码

import SwiftUI

struct Rows: View {
    @State private var stopScrolling = false
    var dataRows: [RowData] = []
    
    init() {
        for i in 0...1000 {
            dataRows.append(RowData(id: i))
        }
    }
    
    var body: some View {
        ScrollViewReader { scrollView in
            ZStack(alignment: .bottomTrailing) {
                List(dataRows) { row in
                    NavigationLink {
                    } label: {
                        Row(data: row)
                    }
                }
                .background(
                    ScrollViewStopper(stopScrolling: $stopScrolling)
                )
                Button("Scroll To Top") {
                    print("button pressed")
                    // 先强制停止滚动
                    stopScrolling = true
                    // 延迟调用scrollTo,确保滚动已停止
                    DispatchQueue.main.async {
                        scrollView.scrollTo(0)
                    }
                }
                .buttonStyle(.bordered)
            }
        }
    }
}

struct Row: View {
    var data: RowData
    
    var body: some View {
        Text(String(data.id))
    }
}

struct RowData: Identifiable {
    var id: Int
}

// 用来控制UIScrollView滚动状态的组件
struct ScrollViewStopper: UIViewRepresentable {
    @Binding var stopScrolling: Bool
    
    func makeUIView(context: Context) -> UIView {
        UIView()
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        guard stopScrolling else { return }
        
        // 找到List对应的UIScrollView
        if let scrollView = uiView.superview?.superview as? UIScrollView {
            // 强制停止滚动
            scrollView.setContentOffset(scrollView.contentOffset, animated: false)
        }
        // 重置状态,避免重复触发
        stopScrolling = false
    }
}

代码说明

  • ScrollViewStopper通过UIViewRepresentable嵌入到List的背景中,利用视图更新机制监听stopScrolling状态变化
  • 当stopScrolling变为true时,找到底层的UIScrollView,调用setContentOffset(_:animated:)并传入当前偏移量、关闭动画,以此强制停止滚动
  • 点击按钮时,先设置stopScrolling = true触发停止操作,再通过DispatchQueue.main.async确保滚动停止后调用scrollTo(),保证操作顺序正确

这样修改后,无论列表是否处于减速滚动状态,点击按钮都能立即停止滚动并跳转到顶部。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:47:30