iOS 16.0下优化ScrollView滚动值获取方案咨询
优化iOS 16 ScrollView滚动值获取方案(适配天气App折叠动画)
需求:获取垂直ScrollView的滚动偏移值,用于实现类似苹果天气App的块折叠动画,基于iOS 16.0开发,现有实现方案冗余,需要更简洁的写法。
现有未优化代码(含拼写修正)
ScrollView(.vertical) { VStack { Rectangle() .frame(width: 100, height: 100) } .background( GeometryReader { proxy in Color.clear.preference( key: ViewOffsetKey.self, value: -proxy.frame(in: .named("scroll")).origin.y ) } ) .onPreferenceChange(ViewOffsetKey.self) { mainScrollValue = $0 } } .coordinateSpace(name: "scroll") .scrollIndicators(.never) // 需额外定义的PreferenceKey struct ViewOffsetKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } }
优化后的简洁实现
方案1:简化层级与逻辑
把GeometryReader直接绑定到ScrollView顶层容器,同时精简PreferenceKey的定义,利用系统内置坐标空间减少冗余:
// 精简后的PreferenceKey struct ScrollOffsetKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {} } // 优化后的ScrollView代码 ScrollView(.vertical) { VStack { Rectangle() .frame(width: 100, height: 100) // 可添加更多需要参与折叠动画的视图 } .background( GeometryReader { proxy in Color.clear.preference( key: ScrollOffsetKey.self, value: proxy.frame(in: .scrollView).minY ) } ) } .coordinateSpace(name: .scrollView) // 使用系统内置坐标空间,避免自定义字符串 .scrollIndicators(.never) .onPreferenceChange(ScrollOffsetKey.self) { scrollOffset in // 直接用滚动偏移值实现折叠动画 // 示例:根据偏移量收缩视图高度 // collapsedHeight = max(100 - scrollOffset, 40) }
优化点说明
- 采用系统内置的
.scrollView坐标空间名,避免自定义字符串的冗余与潜在错误 - 简化PreferenceKey的
reduce方法(单视图场景下无需合并值) - 调整滚动值计算逻辑:直接取
proxy.frame(in: .scrollView).minY,无需取反,滚动时minY随视图上移自然减小,逻辑更直观
适配天气App折叠动画的思路
拿到滚动偏移值后,可通过以下方式实现块折叠效果:
- 根据偏移量动态修改视图的
frame(height:),实现高度收缩 - 使用
clipShape结合offset裁剪视图显示区域 - 配合
opacity实现渐变隐藏效果 - 给多个折叠块设置不同偏移阈值,实现分层递进的动画效果
内容的提问来源于stack exchange,提问作者Jan Ivashenko
相关产品推荐
相关产品推荐

