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

iOS 17中内容重排时如何更新scrollPosition?

解决iOS 17 ScrollView scrollPosition(id:)数组重排时的状态不一致问题

在使用iOS 17的scrollPosition(id:)修饰符实现分页ScrollView时,当数据源数组items重排后,会出现scrollPosition保留旧值,但界面显示新数组首个元素的不一致问题。比如初始数组为[item1, item2, item3, item4]且当前查看item1,数组重排为[item3, item1, item2, item4]后,scrollPosition仍为item1,但界面显示的是item3。

解决方案

通过ScrollViewReader监听滚动视图的可见区域,结合数组变化的回调,同步更新scrollPosition到当前显示的元素:

var items: [Item]
@State var scrollPosition: Item?

ScrollViewReader { proxy in
    ScrollView(.horizontal) {
        HStack(spacing: 0) {
            ForEach(items, id: \.self) { item in
                ItemView(for: item)
                    .containerRelativeFrame([.horizontal, .vertical])
                    .id(item) // 绑定元素唯一标识,与scrollPosition跟踪的id对应
            }
        }
        .scrollTargetLayout()
    }
    .ignoresSafeArea()
    .scrollIndicators(.hidden)
    .scrollPosition(id: $scrollPosition)
    .scrollTargetBehavior(.paging)
    .onChange(of: items) { _, newItems in
        // 获取当前可见区域的首个元素id,同步到scrollPosition
        if let visibleItem = proxy.visibleIds.first as? Item {
            scrollPosition = visibleItem
        }
    }
}

代码说明

  1. ScrollViewReader:提供访问滚动视图内部状态的能力,可获取当前可见视图的id集合。
  2. .id(item):为每个ItemView绑定与元素本身一致的id,确保visibleIds能直接映射到Item类型。
  3. onChange(of: items):监听数组变化,一旦数组重排,立即获取当前可见的首个元素,将其赋值给scrollPosition,实现状态与界面的同步。

额外注意事项

  • 确保Item类型遵循Hashable协议,这是scrollPosition(id:)和ForEach正常工作的前提。
  • 如果数组重排后需要保持滚动到原元素的位置而非回到开头,可调整逻辑:检查原scrollPosition是否存在于新数组中,若存在则通过proxy.scrollTo(scrollPosition)保持滚动位置,同时同步状态;若不存在再切换到首个元素。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 14:05:21