IOS SwiftUI中ScrollView嵌套引起的滑动距离监听实效解决方案 文章目录一、前言二、核心代码一、前言在IOS中使用SwiftUI进行ScrollView滑动嵌套处理的时候想要监听某个滑动组件的滑动距离时候会出现外部滑动控件监听失效(或者距离不是真实的)的问题这里将解决方式记录如下。相关效果如下二、核心代码NestedScrollViews,swift//// NestedScrollViewOffsetTracker.swift// 解决SwiftUI中嵌套ScrollView无法监听滚动距离的问题//// 功能说明// 1. 可靠监听嵌套ScrollView的滚动距离// 2. 处理内外层ScrollView的手势冲突// 3. 提供清晰的滚动距离数值//importSwiftUI// 滚动偏移管理器classScrollOffsetManager:ObservableObject{PublishedvarouterOffset:CGFloat0PublishedvarinnerOffset:CGFloat0}// 外层滚动视图structOuterScrollView:View{ObservedObjectvarmanager:ScrollOffsetManagerStateprivatevaranchorFrame:CGRect.zerovarbody:someView{ScrollView{VStack(spacing:20){// 用于追踪的锚点视图Color.clear.frame(height:1).background(// GeometryReader { proxy in// Color.clear// .onAppear {// anchorFrame proxy.frame(in: .global)// }// .onChange(of: proxy.frame(in: .global)) { newFrame in// // 计算滚动偏移初始位置 - 当前位置// manager.outerOffset anchorFrame.minY - newFrame.minY// }// }GeometryReader{proxyin// 优化逻辑防止过早获取滚动位置Color.clear.onAppear{// 延迟设置锚点框架确保视图已经稳定DispatchQueue.main.asyncAfter(deadline:.now()0.1){anchorFrameproxy.frame(in:.global)// 确保初始偏移量为0manager.outerOffset0debugPrint(YM----初始锚点位置:\(anchorFrame.minY))}}.onChange(of:proxy.frame(in:.global)){newFramein// 只有当锚点框架已经设置后才更新偏移量if!anchorFrame.isEmpty{// 计算滚动偏移初始位置 - 当前位置manager.outerOffsetanchorFrame.minY-newFrame.minYdebugPrint(YM----列表滚动位置:\(manager.outerOffset))}}})Text(外层滚动距离:\(manager.outerOffset,specifier:%.2f)).font(.title).padding().background(Color.yellow).cornerRadius(8)// 内层滚动视图InnerScrollView(manager:manager).frame(height:400).background(Color.gray.opacity(0.1)).cornerRadius(12)ForEach(1..20){iinText(外层内容\(i)).frame(maxWidth:.infinity).padding().background(Color.green).foregroundColor(.white).cornerRadius(8)}}.padding()}.onAppear{// 重置滚动偏移manager.outerOffset0// 如果有groupId则滚动到对应位置// if let groupId groupId {// DispatchQueue.main.asyncAfter(deadline: .now() 0.2) {// withAnimation {// proxy.scrollTo(groupId, anchor: .center)// }//}//}}}}// 内层滚动视图structInnerScrollView:View{ObservedObjectvarmanager:ScrollOffsetManagerStateprivatevaranchorFrame:CGRect.zerovarbody:someView{ScrollView{VStack(spacing:15){// 用于追踪的锚点视图Color.clear.frame(height:1).background(GeometryReader{proxyinColor.clear.onAppear{anchorFrameproxy.frame(in:.global)}.onChange(of:proxy.frame(in:.global)){newFramein// 计算滚动偏移初始位置 - 当前位置manager.innerOffsetanchorFrame.minY-newFrame.minY}})Text(内层滚动距离:\(manager.innerOffset,specifier:%.2f)).font(.title).padding().background(Color.cyan).cornerRadius(8)ForEach(1..30){iinText(内层内容\(i)).frame(maxWidth:.infinity).padding().background(Color.blue).foregroundColor(.white).cornerRadius(8)}}.padding()}// 确保内层手势优先.highPriorityGesture(DragGesture())}}// 主视图structNestedScrollViews:View{StateObjectprivatevarscrollManagerScrollOffsetManager()varbody:someView{OuterScrollView(manager:scrollManager)}}structNestedScrollViews_Previews:PreviewProvider{staticvarpreviews:someView{NestedScrollViews()}}