SwiftUI在ScrollView内用GeometryReader致滚动卡顿、CPU占用过高求助
解决ScrollView滚动卡顿与偏移显示问题
问题根源
你当前的实现中,GeometryReader的闭包会在每一次视图刷新时执行,里面的Task会频繁更新@State var offset,导致CustomTextView不断重绘。再加上5000个列表项的滚动触发大量视图计算,直接把CPU拉满,造成滚动卡顿。
优化方案
改用PreferenceKey结合ScrollView的坐标空间来传递偏移值,这种方式能大幅减少不必要的状态更新和视图重绘,同时精准获取滚动偏移:
- 定义自定义
PreferenceKey,用于传递滚动偏移数据 - 在
ScrollView中指定专属坐标空间 - 在
CustomTextView里通过GeometryReader将自身的坐标作为偏好值发送 - 在
ScrollView层级监听偏好值变化,更新偏移量
修改后的完整代码
import SwiftUI // 自定义PreferenceKey,用于传递偏移值 struct OffsetPreferenceKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } } struct ContentView: View { @State private var scrollOffset: CGFloat = 0 var body: some View { ScrollView { CustomTextView() .onPreferenceChange(OffsetPreferenceKey.self) { newValue in scrollOffset = newValue } VStack { ForEach(0..<5000, id: \.self) { i in HStack { Text("\(i)") Spacer() } .padding() .background(Color.red) } } } .coordinateSpace(name: "ScrollViewSpace") } } struct CustomTextView: View { var body: some View { Text("\(scrollOffset)") .frame(height: 100.0) .frame(maxWidth: .infinity) .background( GeometryReader { geo in Color.gray .preference( key: OffsetPreferenceKey.self, value: geo.frame(in: .named("ScrollViewSpace")).minY ) } ) } }
关键优化点
- PreferenceKey传递:通过偏好值传递偏移,避免了
@State变量在子视图中频繁更新导致的重绘连锁反应 - 专属坐标空间:使用
.coordinateSpace(name:)确保偏移计算的准确性,不受其他视图布局影响 - 减少重绘触发:只有当偏移值真正变化时,才会更新
Text的显示,大幅降低CPU占用
内容的提问来源于stack exchange,提问作者simonchan
相关产品推荐
相关产品推荐

