在体外访问 SwiftUI 视图中的状态变量
Accessing state variable in SwiftUI View outside the body
我有一个内容视图,我想动态跟踪高度。
我已经实现了这个解决方案,但是我遇到了这个异常:
Fatal error: Accessing State outside View.body: file
我该怎么做才能让 keyboardHeight 动态更新我的 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)
}
}
}
错误消息几乎准确地说明了问题所在。但是,尽管您不能访问主体函数(或从主体调用的函数)外部的状态变量,但您可以访问可观察对象。因此,只需将 @State 更改为 @ObservedObject 并定义一个微小的 class,就足以使其工作。
请注意,此解决方案旨在保持您的工作流程理念完整无缺。虽然,还有其他方法可以完成同样的事情。
import SwiftUI
import Combine
class Model: ObservableObject {
@Published var keyboardHeight: CGFloat = 0
}
struct ContentView: View {
@ObservedObject var model = Model()
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: model)
.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: model.keyboardHeight)
}
}
}
我有一个内容视图,我想动态跟踪高度。
我已经实现了这个解决方案,但是我遇到了这个异常:
Fatal error: Accessing State outside View.body: file
我该怎么做才能让 keyboardHeight 动态更新我的 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)
}
}
}
错误消息几乎准确地说明了问题所在。但是,尽管您不能访问主体函数(或从主体调用的函数)外部的状态变量,但您可以访问可观察对象。因此,只需将 @State 更改为 @ObservedObject 并定义一个微小的 class,就足以使其工作。
请注意,此解决方案旨在保持您的工作流程理念完整无缺。虽然,还有其他方法可以完成同样的事情。
import SwiftUI
import Combine
class Model: ObservableObject {
@Published var keyboardHeight: CGFloat = 0
}
struct ContentView: View {
@ObservedObject var model = Model()
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: model)
.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: model.keyboardHeight)
}
}
}