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 } } }
代码说明
- ScrollViewReader:提供访问滚动视图内部状态的能力,可获取当前可见视图的id集合。
- .id(item):为每个
ItemView绑定与元素本身一致的id,确保visibleIds能直接映射到Item类型。 - onChange(of: items):监听数组变化,一旦数组重排,立即获取当前可见的首个元素,将其赋值给
scrollPosition,实现状态与界面的同步。
额外注意事项
- 确保
Item类型遵循Hashable协议,这是scrollPosition(id:)和ForEach正常工作的前提。 - 如果数组重排后需要保持滚动到原元素的位置而非回到开头,可调整逻辑:检查原
scrollPosition是否存在于新数组中,若存在则通过proxy.scrollTo(scrollPosition)保持滚动位置,同时同步状态;若不存在再切换到首个元素。
内容的提问来源于stack exchange,提问作者Nicolas Gimelli
相关产品推荐
相关产品推荐

