在SwiftUI视图中访问主体外部的状态变量

在SwiftUI视图中访问主体外部的状态变量,swiftui,combine,Swiftui,Combine,我有一个内容视图,我想动态跟踪高度 我已实施此解决方案,但遇到以下例外情况: 致命错误:访问视图外部的状态。正文:文件 如何使键盘高度动态更新我的UI struct ContentView: View { @State var keyboardHeight: CGFloat = 0 var cancellables: Set<AnyCancellable> = [] init() { NotificationCenter.default.p

我有一个内容视图,我想动态跟踪高度

我已实施此解决方案,但遇到以下例外情况:

致命错误:访问视图外部的状态。正文:文件

如何使键盘高度动态更新我的UI

struct ContentView: View {

    @State var keyboardHeight: CGFloat = 0
    var cancellables: Set<AnyCancellable> = []

    init() {
        NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)
        .merge(with: NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification))
        .compactMap({ notification in
          guard let keyboardFrameValue: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return nil }
          let keyboardFrame = keyboardFrameValue.cgRectValue
          if keyboardFrame.origin.y == UIScreen.main.bounds.height {
            return 0
          } else {
            return keyboardFrame.height - (UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0)
          }
        })
        .assign(to: \.keyboardHeight, on: self)
        .store(in: &cancellables)
    }

    var body: some View {
        VStack{
            ZStack(alignment: Alignment.bottom) {
                List {
                    Text("Default text").foregroundColor(Color.red)
                }
                TextField("Placeholder", text: .constant(""))
                    .frame(minHeight: 30)
                    .cornerRadius(8.0)
                    .padding(10)
                    .background(Color.blue)
            }
            Spacer()
                .frame(height: keyboardHeight)
        }
    }
}
struct ContentView:View{
@状态变量键盘高度:CGFloat=0
变量可取消项:Set=[]
init(){
NotificationCenter.default.publisher(适用于:UIResponder.keyboardWillChangeFrameNotification)
.merge(与:NotificationCenter.default.publisher(用于:UIResponder.keyboardWillHideNotification))
.compactMap({中的通知)
guard let keyboardFrameValue:NSValue=notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey]作为?NSValue else{return nil}
让keyboardFrame=keyboardFrameValue.cgRectValue
如果keyboardFrame.origin.y==UIScreen.main.bounds.height{
返回0
}否则{
返回keyboardFrame.height-(UIApplication.shared.windows.first?.safeAreaInsets.bottom±0)
}
})
.分配(至:\.键盘高度,打开:self)
.store(在:&可取消项中)
}
var body:一些观点{
VStack{
ZStack(对齐:对齐.底部){
名单{
文本(“默认文本”).foregroundColor(颜色.红色)
}
文本字段(“占位符”,文本:。常量(“”)
.框架(最小高度:30)
.转弯半径(8.0)
.填充(10)
.背景(颜色.蓝色)
}
垫片()
.框架(高度:键盘高度)
}
}
}

错误消息几乎准确地说明了问题所在。然而,尽管不能访问body函数(或从body调用的函数)之外的状态变量,但可以访问可观察对象。因此,通过@ObservedObject简单地更改@State并定义一个小类,就足以让它工作

请注意,此解决方案是为了保持您的工作流想法完好无损。尽管如此,还有其他方法可以完成同样的事情

导入快捷界面
进口联合收割机
类模型:ObservieObject{
@已发布的var键盘高度:CGFloat=0
}
结构ContentView:View{
@ObservedObject var模型=模型()
变量可取消项:Set=[]
init(){
NotificationCenter.default.publisher(适用于:UIResponder.keyboardWillChangeFrameNotification)
.merge(与:NotificationCenter.default.publisher(用于:UIResponder.keyboardWillHideNotification))
.compactMap({中的通知)
guard let keyboardFrameValue:NSValue=notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey]作为?NSValue else{return nil}
让keyboardFrame=keyboardFrameValue.cgRectValue
如果keyboardFrame.origin.y==UIScreen.main.bounds.height{
返回0
}否则{
返回keyboardFrame.height-(UIApplication.shared.windows.first?.safeAreaInsets.bottom±0)
}
})
.分配(至:\.键盘高度,在:模型上)
.store(在:&可取消项中)
}
var body:一些观点{
VStack{
ZStack(对齐:对齐.底部){
名单{
文本(“默认文本”).foregroundColor(颜色.红色)
}
文本字段(“占位符”,文本:。常量(“”)
.框架(最小高度:30)
.转弯半径(8.0)
.填充(10)
.背景(颜色.蓝色)
}
垫片()
.框架(高度:型号.键盘高度)
}
}
}

您可以将发布者创建为私有财产(无需
分配给
),并使用
onReceive
在视图主体中订阅它。我相信这会给你你想要的。其他方法可以做同样的事情吗?是的,但是这种方式有什么问题吗?