iOS SwiftUI:视图出现时根据视图高度更新变量
解决SwiftUI中视图高度获取与State变量更新问题
错误原因分析
- 第一个写法报错:
GeometryReader的闭包要求返回View类型,直接在闭包里写profileViewHeight = geo.size.height会返回Void,不符合View协议,因此报错Type '()' cannot conform to 'View'。 - onAppear方式异常:
onAppear触发时视图可能还未完成最终布局,此时获取的高度不是视图渲染后的真实高度,导致UI异常。
正确解决方案:使用PreferenceKey捕获视图高度
通过自定义PreferenceKey来传递视图布局完成后的真实高度,具体步骤如下:
1. 定义PreferenceKey
首先创建一个用于传递高度值的PreferenceKey:
struct ViewHeightKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } }
2. 修改视图结构,捕获并传递高度
将GeometryReader放到目标视图的background中,通过preference传递高度值,再用onPreferenceChange更新profileViewHeight:
userProfileView(uid: uid, userid: self.$userid, offsetMenu: self.$offsetMenu, closeThisView: closeThisView) .frame(width: UIScreen.main.bounds.width) .background(Color.teal) .padding(.bottom, profileViewOffset) .offset(y: profileViewOffset) .zIndex(2) .background( // 用透明背景的GeometryReader获取视图高度 GeometryReader { geo in Color.clear .preference(key: ViewHeightKey.self, value: geo.size.height) } ) // 监听高度变化,更新State变量 .onPreferenceChange(ViewHeightKey.self) { newHeight in profileViewHeight = newHeight }
方案优势
- 避免了
GeometryReader闭包返回类型不匹配的问题; background中的GeometryReader会跟随目标视图的布局,获取到的是视图渲染完成后的真实高度;onPreferenceChange会在视图高度发生变化时实时更新变量,确保UI状态准确。
内容的提问来源于stack exchange,提问作者Coddo
相关产品推荐
相关产品推荐

