iPhoneX and iPhone 8 keyboard height are different
Asked Answered
S

6

46

I use below code to get keyboard height. Then use this height to calculate the frame of an UIView to make sure this UIView just on the top of the keyboard.

But in iPhoneX simulator the output is 333 and the iPhone 8 simulator is 258.

ISSUE: If use rect.height as the keyboard height for iPhone 8 simulator then the layout is correct. For iPhone X there's a gap between the UIView and keyboard. Which means 333 is higher than the real keyboard height in iPhone X.

What's the reason of the height are different? And how to get the correct keyboard height?

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)


@objc func keyboardWillShow(_ notification: NSNotification) {
        if let rect = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
           print(rect.height)
        } 
    }

Like this image, the green border should be the extra part. Actually, I need the red part just on the top of keyboard without the green rect gap. enter image description here

EDIT

OK, with @Craig's help I found this method only called by iPhone X. So I update frame here. Just paste the code here.

The safe area bottom height is 22.0 seems not correct.

override func viewSafeAreaInsetsDidChange() {
    if #available(iOS 11.0, *) {
        super.viewSafeAreaInsetsDidChange()
        view.safeAreaInsets.bottom // This value is the bottom safe area place value.
    }
}

EDIT2 Normally view.safeAreaInsets.bottom should be 34.0, but if you are using container view this value can be different like mine is 22.0.

Sherrellsherrer answered 26/9, 2017 at 7:42 Comment(6)
what is your issue actually? you ask for an opinion-based speculation in your question.Destalinization
You can always use rect.height to calculate what's remaining?Elnora
@Destalinization I edited my question. My question is i can't get correct keyboard height by rect.height from the notification.Sherrellsherrer
@zcui93 rect.height should be the keyboard height normally.Sherrellsherrer
@zcui93 You are right, i think for iPhone X the rect height isn't keyboard height anymore. Should plus the bottom part.Sherrellsherrer
I was using UIKeyboardFrameBeginUserInfoKey instead of UIKeyboardFrameEndUserInfoKey. This gave me different height values on consecutive keyboard toggles. But the first key was working on non-iPhone-X just fine.... strangeThis
B
39

The keyboard height for both iPhone X and iPhone 8 should be correct. I can only guess that maybe you have a problem in your code for locating the "red part", and your assumption was that the keyboard height was incorrect whereas the problem was actually in the location of the view. Now - the reason for the location problem? My second guess is the red part is pinned to the bottom safe area layout guide, which on the iPhone 8 is 0, but on the iPhone X is inset 34 points.

See this image to illustrate both the difference in keyboard heights and that it is possible to draw a rectangle just above the keyboard using the keyboard height from the keyboard height reported in the NSNotification for the keyboardWillShow method:

enter image description here

If you want to share your code / constraints for positioning the red view, I should be able to show you the problem.

--Edit: For anyone interested to know how I extract the drew the red rectangle, I go into it in a blog post here.

Berty answered 26/9, 2017 at 9:59 Comment(2)
Yeah, i think you are right. "The inset is 34 pt", i tried view.safeAreaInset in both iPhone 8 and iPhone X seems all (0,0,0,0), how to get this value?Sherrellsherrer
If you tried it in viewDidLoad, it seems as though this value isn't yet set at this point. You can override viewSafeAreaInsetsDidChange to see this value: override func viewSafeAreaInsetsDidChange() { print(view.safeAreaInsets) }Berty
R
48

While Craig's answer is correct, you might not want to pin your view to view.bottom or the bottomLayoutGuide rather than the safe area bottom (especially if your keyboard is not always open, and you don't want your views to cover the Home Indicator area).

Here is a fix for these cases. It deducts the height of the bottom inset of the safe area from the height of the keyboard:

var keyboardHeight = ... // Get the keyboard height from keyboard notification

if #available(iOS 11.0, *) {
    let bottomInset = view.safeAreaInsets.bottom
    keyboardHeight -= bottomInset
}
Riffraff answered 8/2, 2018 at 19:48 Comment(0)
B
39

The keyboard height for both iPhone X and iPhone 8 should be correct. I can only guess that maybe you have a problem in your code for locating the "red part", and your assumption was that the keyboard height was incorrect whereas the problem was actually in the location of the view. Now - the reason for the location problem? My second guess is the red part is pinned to the bottom safe area layout guide, which on the iPhone 8 is 0, but on the iPhone X is inset 34 points.

See this image to illustrate both the difference in keyboard heights and that it is possible to draw a rectangle just above the keyboard using the keyboard height from the keyboard height reported in the NSNotification for the keyboardWillShow method:

enter image description here

If you want to share your code / constraints for positioning the red view, I should be able to show you the problem.

--Edit: For anyone interested to know how I extract the drew the red rectangle, I go into it in a blog post here.

Berty answered 26/9, 2017 at 9:59 Comment(2)
Yeah, i think you are right. "The inset is 34 pt", i tried view.safeAreaInset in both iPhone 8 and iPhone X seems all (0,0,0,0), how to get this value?Sherrellsherrer
If you tried it in viewDidLoad, it seems as though this value isn't yet set at this point. You can override viewSafeAreaInsetsDidChange to see this value: override func viewSafeAreaInsetsDidChange() { print(view.safeAreaInsets) }Berty
C
6

This works for every device and iOS version so far

- (void)keyboardWillShown:(NSNotification*)aNotification
{
        NSDictionary* info = [aNotification userInfo];
        CGFloat kbHeight = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
        CGFloat safeAreaBottomInset = 0;
        if (@available(iOS 11.0, *)) {
            safeAreaBottomInset = self.view.safeAreaInsets.bottom;
        }
        self.containerViewBottomConstraint.constant += (kbHeight - safeAreaBottomInset); //In my case I use a constraint to adapt the UI when the keyboard is presented
        [self.view layoutIfNeeded];
}
Cephalothorax answered 20/11, 2018 at 10:33 Comment(1)
Just pin to Superview.Bottom constraint. Not safe area.Cobwebby
P
0

I also faced this problem. What I did, simply I check keyboard that is different on iPhone 7 and iPhone X. I just add some default margin with keyboard height. Now It is working fine on every device.

Posture answered 29/10, 2018 at 13:2 Comment(1)
Adding magic fixed numbers should NEVER be a viable solution.Transept
H
0

override func viewDidLoad() { super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
//Here keyboard is without any toolbar and suggestions boxes
@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        let keyboardHeight = ((keyboardSize.height) > 240) ? 220 :  (keyboardSize.height - 47)
        self.view.layoutIfNeeded()
    }

}
Hour answered 26/7, 2019 at 7:9 Comment(1)
Using magic number like that is NOT pretty. What happends when Apple decides to change the height of i.e. the home bar? They have done so before...Transept
C
0

It can get tricky if your view is embedded as a child view (like TabBar or PagerViewController) and you don't have access to the parent (if you're a framework for example).

This can be also calculated by the diff of current view height with the window height and the Y position of the current view:

Swift:

func calculateHeightOffsetFromContainer() -> CGFloat {
    let convertedYInParent = self.view.convert(self.view.frame, to: nil).origin.y
    let offsetInViewHeights = UIScreen.main.bounds.height - self.view.frame.height
    return offsetInViewHeights - convertedYInParent;
}

Usage:

let keyboardYPosition = keyboardFrame.height - offsetFromConteiner

Objective C:

- (CGFloat)calculateHeightOffsetFromContainer {
    CGFloat convertedYInParent = [self.view convertRect: self.view.frame toView: nil].origin.y;
    CGFloat offsetInViewHeights = [UIScreen mainScreen].bounds.size.height - self.view.frame.size.height;
    return offsetInViewHeights - convertedYInParent;
}

Usage:

CGFloat keyboardYPosition = keyboardFrame.size.height - offsetFromConteiner;
Cuenca answered 17/11, 2021 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.