Xcode
iOS
Swift
Xcode8
swift3

【Swift】UITextField, UITextViewがキーボードで隠れるのを防ぐ(UIScrollViewを使わずに)

More than 1 year has passed since last update.

はじめに

UITextFieldを画面に配置したはいいけど、下の写真のようにキーボードが出てくると隠れるというのはよくあることだと思います。
UIScrollViewを使ったりしている方法がありますが、画面にUIScrollViewを配置したりするのは面倒なので、画面をそもそもずらす方法を見つけたので、それをXcode8, Swift3で実装しました。

アートボード 1.png

コード

実装前

ViewController.swift
import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var firstTextField: UITextField! {

        didSet {

            firstTextField.delegate = self
        }
    }


    @IBOutlet var secondTextField: UITextField! {

        didSet {

            secondTextField.delegate = self
        }
    }

    override func viewDidLoad() {

        super.viewDidLoad()
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {

        textField.resignFirstResponder()
        return true
    }
}

これだと、キーボードがReturnキーを押したときに下がるだけの実装です。
ここから、NotificationCenterを使って、キーボードが表示されたり消えたりすることを検知します。
そして、キーボードが表示されたり消えたときに、animate(withDuration duration: TimeInterval, animations: @escaping () -> Swift.Void)を使って、画面全体をずらします。

実装

まずNotificationを設定するメソッドと削除するメソッドを用意し、それぞれviewWillAppear(_ animated: Bool)viewWillDisappear(_ animated: Bool)で呼び出します。
それぞれのメソッドは以下のように設定します。

ViewController.swift
    // Notificationを設定
    func configureObserver() {

        let notification = NotificationCenter.default
        notification.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        notification.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    // Notificationを削除
    func removeObserver() {

        let notification = NotificationCenter.default
        notification.removeObserver(self)
    }

Notificationに設定したselectorのメソッドを設定します。

ViewController.swift
    // キーボードが現れた時に、画面全体をずらす。
    func keyboardWillShow(notification: Notification?) {

        let rect = (notification?.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        let duration: TimeInterval? = notification?.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
        UIView.animate(withDuration: duration!, animations: { () in
            let transform = CGAffineTransform(translationX: 0, y: -(rect?.size.height)!)
            self.view.transform = transform

        })
    }

    // キーボードが消えたときに、画面を戻す
    func keyboardWillHide(notification: Notification?) {

        let duration: TimeInterval? = notification?.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? Double
        UIView.animate(withDuration: duration!, animations: { () in

            self.view.transform = CGAffineTransform.identity
        })
    }

以上で、完了です。

以下にすべてのコードを載せておきます。

完成品

ViewController.swift
import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var firstTextField: UITextField! {

        didSet {

            firstTextField.delegate = self // デリゲートをセット
        }
    }


    @IBOutlet var secondTextField: UITextField! {

        didSet {

            secondTextField.delegate = self // デリゲートをセット
        }
    }

    override func viewDidLoad() {

        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated)
        self.configureObserver()

    }

    override func viewWillDisappear(_ animated: Bool) {

        super.viewWillDisappear(animated)
        self.removeObserver() // Notificationを画面が消えるときに削除
    }

    // Notificationを設定
    func configureObserver() {

        let notification = NotificationCenter.default
        notification.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        notification.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    // Notificationを削除
    func removeObserver() {

        let notification = NotificationCenter.default
        notification.removeObserver(self)
    }

    // キーボードが現れた時に、画面全体をずらす。
    func keyboardWillShow(notification: Notification?) {

        let rect = (notification?.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        let duration: TimeInterval? = notification?.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
        UIView.animate(withDuration: duration!, animations: { () in
            let transform = CGAffineTransform(translationX: 0, y: -(rect?.size.height)!)
            self.view.transform = transform

        })
    }

    // キーボードが消えたときに、画面を戻す
    func keyboardWillHide(notification: Notification?) {

        let duration: TimeInterval? = notification?.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? Double
        UIView.animate(withDuration: duration!, animations: { () in

            self.view.transform = CGAffineTransform.identity
        })
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {

        textField.resignFirstResponder() // Returnキーを押したときにキーボードを下げる
        return true
    }
}


参考URL

TextViewをキーボードに隠されず、高さが動的に変わるようにする

サンプルコード

https://github.com/ShinokiRyosei/Keyboard-Sampler