SwiftUI中ScrollView调用scrollTo无法滚动到底部是什么原因?
问题根源
你的实现有两个核心遗漏,导致滚动失效:
- 没有给列表内的单个条目视图绑定匹配的id:
ScrollViewProxy的scrollTo方法依赖视图上的.id()标记定位,你只在ForEach里声明了用item.id做数据id,但是没有给实际渲染的条目视图设置对应id,proxy找不到目标视图自然不会执行滚动。 - 滚动触发时机过早:
onChange监听到lastItemID变化时,SwiftUI还没完成新增条目的布局渲染,这时候调用滚动方法,proxy还拿不到新条目的位置信息,操作会直接无效。onAppear里的滚动调用也有同样的时机问题。
修复代码
ScrollViewReader { proxy in ScrollView { VStack { LazyVGrid(columns: twoColumnGrid, alignment: .leading) { ForEach(roomData.newItems, id: \.id) { item in VStack{ ItemView(lastDeleted: $recentDeletedItems, item: item, roomData: roomData) } .id(item.id) // 给每个条目绑定对应id,供proxy定位 } } } } .onChange(of: roomData.lastItemID) { id in print("ID Changed: \(String(describing: id))") // 切到主线程异步执行,等布局完成后再触发滚动 DispatchQueue.main.async { withAnimation { proxy.scrollTo(id, anchor: .bottom) } } } .onAppear { DispatchQueue.main.async { proxy.scrollTo(roomData.lastItemID, anchor: .bottom) } } }
额外注意
- 不要把
.id()设置在ScrollView、LazyVGrid或者外层的VStack上,必须绑定在ForEach内对应单个条目的根视图上,否则id定位会失效。 - 如果后续加了删除条目逻辑,用同样的滚动逻辑也能生效,只要保证目标视图的id和传入scrollTo的参数一致即可。
内容的提问来源于stack exchange,提问作者user7894007
相关产品推荐
相关产品推荐

