I'm using UIResponder.keyboardWillShowNotification
and the user info it provides to perform manual keyboard avoidance. Interestingly my method works fine on devices with square screen corners (iPhone SE 3rd Generation) but not on devices with curved corner screens (e.g. iPhone 15 Pro Max). When there's curved corners the height seems to be a bit too large.
I've also tried accounting for the height of the container's bottom safe area but that height didn't exactly match up with the extra height I'm seeing.
import SwiftUI
struct ContentView: View {
@State private var text = ""
@State private var keyboardHeight: CGFloat = .zero
var body: some View {
VStack {
TextField("Test", text: $text)
Color.red
.frame(height: keyboardHeight)
}
.animation(.default.delay(0), value: keyboardHeight)
.frame(maxHeight: .infinity, alignment: .bottom)
.ignoresSafeArea(.keyboard)
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) {
keyboardHeight = ($0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect).height
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
keyboardHeight = .zero
}
}
}
Device with rounded corners (bad):
Device with square corners (good):
It's because of safe area inset at the bottom. Try this:
GeometryReader { geo in // <- wrap inside GeometryReader
VStack {
TextField("Test", text: $text)
.autocorrectionDisabled(true)
Color.red
.frame(height: keyboardHeight)
}
.animation(.default.delay(0), value: keyboardHeight)
.frame(maxHeight: .infinity, alignment: .bottom)
.ignoresSafeArea(.keyboard)
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) {
let height = ($0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect).height
keyboardHeight = height - geo.safeAreaInsets.bottom
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
keyboardHeight = .zero
}
}