Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
385 views
in Technique[技术] by (71.8m points)

iphone - Get height of iOS keyboard without displaying keyboard

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...