[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
    })
}

おしまい。

スポンサーリンク