I'm trying to get the height of the iOS keyboard. I've gone through and used the method involving subscribing to a notification such as detailed here: https://gist.github.com/philipmcdermott/5183731
- (void)viewDidAppear:(BOOL) animated {
[super viewDidAppear:animated];
// Register notification when the keyboard will be show
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
// Register notification when the keyboard will be hide
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardBounds];
// Do something with keyboard height
}
- (void)keyboardWillHide:(NSNotification *)notification {
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardBounds];
// Do something with keyboard height
}
This works fine for when the user actually displays the keyboard.
My problem: I have another view, let's call it micView, that may be presented before the keyboard appears. The user may choose to use the microphone before typing. I would like the micView to be the same height as the keyboard, which is why I need the keyboard's height, but I need it before the keyboard was forced to appear. Thus the UIKeyboardWillShowNotification is not reached before I need to read the value of the height.
My question is: how do I get the height of the keyboard through Notifications, or some other method without ever having the keyboard appear.
I considered explicitly forcing the keyboard to appear in viewDidLoad, so that I can set an instance variable to that value, then hiding it and getting rid of the animations for both things. But is that really the only way to do that?
The top of the keyboard needs to be about 2 inches from the bottom of the *device* as it is held. Prior to the iPhone X, this is easy because all devices used the exact same bezel insets, so it's 216 pts from the bottom of the screen.
Getting the keyboard height with Swift is easy, and can be used when we need to move some content up if the keyboard overlaps it. To get the keyboard height we need to listen for the . keyboardDidShowNotification . When receive this notification we can access the keyboard height from the notification's userInfo .
Via Tap Gesture This is the quickest way to implement keyboard dismissal. Just set a Tap gesture on the main View and hook that gesture with a function which calls view. endEditing . Causes the view (or one of its embedded text fields) to resign the first responder status.
This Swift class provides a turn-key solution that manages all the necessary notifications and initializations, letting you simply call a class method and have returned the keyboard size or height.
Calling from Swift:
let keyboardHeight = KeyboardService.keyboardHeight()
let keyboardSize = KeyboardService.keyboardSize()
Calling from Objective-C:
CGFloat keyboardHeight = [KeyboardService keyboardHeight];
CGRect keyboardSize = [KeyboardService keyboardSize];
If wanting to use this for initial view layout, call this from the viewWillAppear
method of a class where you want the keyboard height or size before the keyboard appears. It should not be called in viewDidLoad, as a correct value relies on your views having been laid out. You can then set an autolayout constraint constant with the value returned from the KeyboardService, or use the value in other ways. For instance, you might want to obtain the keyboard height in prepareForSegue
to assist in setting a value associated with the contents of a containerView being populated via an embed segue.
Note re safe area, keyboard height, and iPhone X:
The value for keyboard height returns the full height of the keyboard, which on the iPhone X extends to the edge of the screen itself, not just to the safe area inset. Therefore, if setting an auto layout constraint value with the returned value, you should attach that constraint to the superview bottom edge, not to the safe area.
Note re hardware keyboard in Simulator:
When a hardware keyboard is attached, this code will provide the on-screen height of that hardware keyboard, that is, no height. This state does need to be accounted for, of course, as this simulates what will occur if you have a hardware keyboard attached to an actual device. Therefore, your layout that is expecting a keyboard height needs to respond appropriately to a keyboard height of zero.
KeyboardService class:
As usual, if calling from Objective-C, you simply need to import the app's Swift bridging header MyApp-Swift.h
in your Objective-C class.
import UIKit
class KeyboardService: NSObject {
static var serviceSingleton = KeyboardService()
var measuredSize: CGRect = CGRect.zero
@objc class func keyboardHeight() -> CGFloat {
let keyboardSize = KeyboardService.keyboardSize()
return keyboardSize.size.height
}
@objc class func keyboardSize() -> CGRect {
return serviceSingleton.measuredSize
}
private func observeKeyboardNotifications() {
let center = NotificationCenter.default
center.addObserver(self, selector: #selector(self.keyboardChange), name: .UIKeyboardDidShow, object: nil)
}
private func observeKeyboard() {
let field = UITextField()
UIApplication.shared.windows.first?.addSubview(field)
field.becomeFirstResponder()
field.resignFirstResponder()
field.removeFromSuperview()
}
@objc private func keyboardChange(_ notification: Notification) {
guard measuredSize == CGRect.zero, let info = notification.userInfo,
let value = info[UIKeyboardFrameEndUserInfoKey] as? NSValue
else { return }
measuredSize = value.cgRectValue
}
override init() {
super.init()
observeKeyboardNotifications()
observeKeyboard()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
Head nod:
The observeKeyboard method here based on the original approach outlined by Peres in the Objective-C answer to this question.
A quick solution that you could use, is the same one used when you want to cache the keyboard (the first time you show it, you get a slight delay...). The library is here. The interesting bits:
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:field];
[field becomeFirstResponder];
[field resignFirstResponder];
[field removeFromSuperview];
So basically is showing it and then hiding it. You could listen for notifications and just get the height
without actually seeing it. Bonus: you get to cache it. :)
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