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

如何获取分页ScrollView内LazyVStack滚动结束时的当前显示项

解决分页ScrollView滚动结束后获取当前显示项的问题

直接用scrollPosition结合onChange替代onAppear,就能解决重复触发和取消滚动不触发的问题,具体实现如下:

实现代码

struct SwippableView: View {
    var data: [VerseModel]
    @State private var currentVerseId: VerseModel.ID? // 跟踪当前滚动到的条目ID
    
    var body: some View {
        ScrollView(.vertical) {
            LazyVStack(spacing: 0) {
                ForEach(data, id: \.id) { verse in
                    VerseView(verse: verse)
                        .padding(0)
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                }
            }
            .scrollTargetLayout()
        }
        .ignoresSafeArea()
        .scrollTargetBehavior(.paging)
        .scrollIndicators(.never)
        .scrollPosition(id: $currentVerseId) // 绑定滚动位置到当前条目的ID
        .onChange(of: currentVerseId) { _, newId in
            guard let newId = newId, let currentVerse = data.first(where: { $0.id == newId }) else {
                return
            }
            print("滚动结束,当前显示的项:\(currentVerse)")
        }
    }
}

方案优势

  • 仅在滚动完全结束后触发,不会像onAppear那样重复调用
  • 即使中途取消滚动(拖拽后松手回弹),也会自动更新到最终停留的条目,避免遗漏触发
  • 分页模式下,scrollPosition会精准匹配当前完全显示的全屏条目

可选:跟踪索引而非ID

如果更倾向于用索引跟踪,可修改代码如下:

struct SwippableView: View {
    var data: [VerseModel]
    @State private var currentIndex: Int? // 跟踪当前滚动到的条目索引
    
    var body: some View {
        ScrollView(.vertical) {
            LazyVStack(spacing: 0) {
                ForEach(Array(data.enumerated()), id: \.element.id) { index, verse in
                    VerseView(verse: verse)
                        .padding(0)
                        .frame(maxWidth: .infinity, maxHeight: .infinity)
                }
            }
            .scrollTargetLayout()
        }
        .ignoresSafeArea()
        .scrollTargetBehavior(.paging)
        .scrollIndicators(.never)
        .scrollPosition(id: $currentIndex) // 绑定滚动位置到当前条目的索引
        .onChange(of: currentIndex) { _, newIndex in
            guard let newIndex = newIndex, newIndex < data.count else {
                return
            }
            let currentVerse = data[newIndex]
            print("滚动结束,当前显示的项:\(currentVerse)")
        }
    }
}

内容的提问来源于stack exchange,提问作者Jaseel.Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:15:07