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):
2
Answers
It’s because of safe area inset at the bottom. Try this:
The extra height comes from the container’s safe area, the area that contains the "home swipe bar" on iPhone 15 and other models.
keyboardFrameEndUserInfoKey
includes the container’s safe area too, but you only ignored the.keyboard
safe area, and that’s why the red area appears higher than what you expect.One workaround is to ignore all safe areas depending on whether the keyboard is showing.
Alternatively, you can avoid using
NotificationCenter
, and do this in pure SwiftUI. All you need is to read the container safe area, and the total safe area, and subtract one from the other.