iOS
Swift
ios11

iOS11でkeyboardの高さを正しく取得する

More than 1 year has passed since last update.

問題

よくScrollView+TextFieldのような画面で、キーボードが隠れないようにするためにキーボードの開閉の通知を受け取ってscrollInsetをいい感じに調整したりする場合があります

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: .UIKeyboardWillHide, object: nil)
    }

    @objc private func keyboardWillShow(_ notification: Notification) {
        guard let userInfo = notification.userInfo as? [String: Any] else {
            return
        }
        guard let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue else {
            return
        }
        guard let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double else {
            return
        }
        let keyboardSize = keyboardInfo.cgRectValue.size
        let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0) //←
        UIView.animate(withDuration: duration, animations: {
            self.scrollView.contentInset = contentInsets
            self.scrollView.scrollIndicatorInsets = contentInsets
            self.view.layoutIfNeeded()
        })
    }

    @objc private func keyboardWillHide(_ notification: Notification) {
        scrollView.contentInset = .zero
        scrollView.scrollIndicatorInsets = .zero
    }

しかし、iOS11だと上記処理のうち、 keyboardSize.height が0になってしまう問題があるようです。

これにハマって、最初の1回目のキーボード表示では高さが取得できていい感じにinsetが調整されるものの、2回目以降、アプリを再起動するまでずっと0になってて... :innocent:

修正方法

UIKeyboardFrameBeginUserInfoKeyUIKeyboardFrameEndUserInfoKey に変更します。

guard let keyboardInfo = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue else {
    return
}

いままでBeginとEndとあってどっち使うんだって思っていたんですけど、Endの方を使っておけば大丈夫そうです。

参考