[Swift] UITextFieldにKeyboardが重なるときだけ全体を上にスライドさせる
環境
- Xcode 10.1
 - Swift 4.2
 - UIScrollViewは使いません
 
Keyboard開閉通知を追加する
Keyboardの開閉タイミングを知りたいのでNotificationを追加します。
class MyView : UIViewController {
    ...省略...
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // Notificationを設定する
        let nc = NotificationCenter.default
        nc.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        nc.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    // NotificationCenterからのキーボード表示通知に伴う処理
    @objc func keyboardWillShow(_ notification: Notification) {
    }
    // NotificationCenterからのキーボード非表示通知に伴う処理
    @objc func keyboardWillHide(_ notification: Notification) {
    }
}
編集対象のTextFieldを保持する
KeyboardがTextFieldに重ならない場合にはスライドしたくないので、これを判別するためにどのTextFieldを編集しているかを覚えておきます。
textFieldShouldBeginEditingを使用してメンバ変数に編集対象のTextFieldを保持しておくようにします。
textFieldShouldBeginEditingを使用したいので、UIViewControllerにはUITextFieldDelegeteを追加します。
class MyView : UIViewController, UITextFieldDelegate {
    ...省略...
    // 編集中のTextFieldを保持する変数
    private var _activeTextField: UITextField? = nil
    // TextFieldの編集直後に呼ばれる
    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        // 編集対象のTextFieldを保存する
        _activeTextField = textField
        return true;
    }
}
Keyboardの開閉に合わせて全体をスライドさせる
Keyboardの開閉に合わせて全体のスライド幅を調整します。
TextFieldとKeyboardが重ならない場合にはスライドさせないように判定をしています。
問答無用でKeyboard分だけスライドしていい場合には判定はいらないので消してください。
// NotificationCenterからのキーボード表示通知に伴う処理
@objc func keyboardWillShowNotification(_ notification: Notification) {
    guard let textField = _activeTextField else {
        return
    }
    let rect = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
    guard let keyboardHeight = rect?.size.height else {
        return
    }
    let mainBoundsSize = UIScreen.main.bounds.size
    let textFieldLimit = textField.frame.origin.y + textField.frame.height + 8.0
    let keyboardLimit = mainBoundsSize.height - keyboardHeight
    if keyboardLimit <= textFieldLimit {
        let duration: TimeInterval? = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double
        UIView.animate(withDuration: duration!, animations: { () in
            self.view.transform = CGAffineTransform(translationX: 0, y: -keyboardHeight)
        })
    }
}
// NotificationCenterからのキーボード非表示通知に伴う処理
@objc func keyboardWillHideNotification(_ notification: Notification) {
    let duration: TimeInterval? = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? Double
    UIView.animate(withDuration: duration!, animations: { () in
        self.view.transform = CGAffineTransform.identity
    })
}
おしまい。




ディスカッション
ピンバック & トラックバック一覧
[…] MEMO このサイトを参考にさせてもらいました。 実際には、上記サイトでは、移動距離の計算をきちんと書いているのですが、そこまでいらないかなぁと思って、適当にしたバージョ […]