1

Like so many other threads here I need to move a view up so its visible while they keyboard is visible and the correct answer seems to be this in most cases:

var isKeyboardVisible = false

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)

}

@objc func keyboardWillShow(notification: NSNotification) {
    if !isKeyboardVisible {
        if let keyboardRectValue = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            let keyboardHeight = keyboardRectValue.height
            if self.view.frame.origin.y == 0 {
                self.view.frame.origin.y -= keyboardHeight
            }
        }

        isKeyboardVisible = true
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if isKeyboardVisible {
        if let keyboardRectValue = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            let keyboardHeight = keyboardRectValue.height
            if self.view.frame.origin.y != 0 {
                self.view.frame.origin.y += keyboardHeight
            }
        }
        isKeyboardVisible = false
    }
}

This however doesn't work if the user uses a custom keyboard. keyboardHeight is 0 if a custom keyboard is used. But if the stock keyboard is used the height seems correct.

Can be reproduced if you install Google GBoard and try to get the height of the keyboard.

I'm quite certain I'm not the only one using a custom keyboard, so I guess there should be some kind of solution for this problem which is dynamic and doesn't include a long if/else list.

Addition 1: I found this answer which suggests to add an inputAccessoryView to the textfield. This makes perfect sense to me as this view will always be exactly above the keyboard. There is how ever two problems with this.

One, content is still being hidden behind the keyboard. Two, if the textfield which is currently focused is behind the keyboard, should I add a duplicate of it to the ´ inputAccessoryView´ so whatever is written is shown in both? This seems like a lot of extra work.

What does apps like whatsapp do to solve this? There must be a universal way to adapt the content to fit above any keyboard (stock or custom) and also not disappear above the top part of the screen!?!?

just_user
  • 11,769
  • 19
  • 90
  • 135
  • 1
    It seems like a common issue for custom keyboards, see: https://stackoverflow.com/questions/36033153/uikeyboardwillshownotification-is-called-three-times. Looks like it sends the keyboardWillShow notification three times and the last call is the one that contains the actual height. – Scriptable Nov 06 '18 at 13:15
  • @just_user use is library.this will solve your problem. https://github.com/hackiftekhar/IQKeyboardManager – Rahuld Nov 06 '18 at 13:36
  • thanks @Rahuld. That will be my backup plan. First I'm hoping for a more elegant and simple solution. – just_user Nov 06 '18 at 14:04
  • @just_user this library is very simple you have only write one line of code in app delegate. – Rahuld Nov 06 '18 at 14:07
  • 1
    @Rahuld yes, but its like magic. I would like to know how it can be solved by code. – just_user Nov 06 '18 at 14:20

1 Answers1

0

So this is the cleanest way I've found.

Swift 4.2

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardShowHide), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardShowHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardShowHide), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

}


@objc func keyboardShowHide(notification: NSNotification) {
    if let keyboardRectValue = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.size.height = UIScreen.main.bounds.height - keyboardRectValue.height
    }
}

Many solutions for getting the the necessary view above the keyboard is to move all the content up and beyond the screen limit. I consider this bad practice there the will be content totally inaccessible to the user outside of the screen as long as the keyboard is visible.

As in my solution above I prefer to adjust the size of the content instead of moving it. So if the content is in a tableview or a scrollview everything will still be available while the keyboard is visible.

If you however prefer that approach just change this line:

self.view.frame.size.height = UIScreen.main.bounds.height - keyboardRectValue.height

for this:

self.view.frame.origin.y = -keyboardRectValue.height
just_user
  • 11,769
  • 19
  • 90
  • 135