I have a content view and I want to track dynamically the height.
I have implemented this solution but i encounter this Exception :
Fatal error: Accessing State outside View.body: file
What can i do to have keyboardHeight dynamic which can update my 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)
}
}
}
The error message is pretty much saying exactly what the problem is. However, although you cannot access State variables outside the body function (or a function called from body), you can access observable objects. So simply changing @State by @ObservedObject and defining a tiny class, is enough to make it work.
Note that this solution is to keep your workflow idea intact. Although, there're other ways to accomplish the same thing.
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)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With