UITextFieldをキーボードが出てきた時に隠れないようにする


はじめに

UITextField, UITextViewはせっかく編集できるのにデフォルトではキーボードが表示されると隠れてしまいます。悲しいですね。。

実装環境

Swift: version 4.1
Xcode: version 9.3
Swiftはおそらく3系でも動きます。

実装方法

テキトーにプロジェクトを作ってください。今回はPlaygroundではなく、xcodeprojectで実装します。

実装① Storyboardに部品の配置

今回はわかりやすいように4つのTextFieldを配置しました。一番下がデフォルトだとキーボードを表示したら隠れます。

実装② Outlet接続

Outlet接続を用意します。最後のactiveTextFieldは、現在編集中のTextFieldを常に代入しておき、キーボードが呼ばれるたびにこの値を利用することで画面を上に動かすので絶対必要です。

ViewController.swift
    @IBOutlet weak var firstTextField: UITextField!
    @IBOutlet weak var secondTextField: UITextField!
    @IBOutlet weak var thirdTextField: UITextField!
    @IBOutlet weak var fourthTextField: UITextField!
    fileprivate var activeTextField: UITextField?

実装③ delegateの設定

ViewControllerのクラスにUITextFieldDelegateを継承させ、

ViewController.swift
class ViewController: UIViewController, UITextFieldDelegate {

viewDidLoadでdelegateを設定しましょう。

ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        //setup delegate
        self.firstTextField.delegate = self
        self.secondTextField.delegate = self
        self.thirdTextField.delegate = self
        self.fourthTextField.delegate = self
    }

実装④ メインの関数の実装

メインの関数を二つ用意します。キーボードが現れる時用とキーボードが隠れる時用です。

ViewController.swift
    @objc private func handleKeyboardWillShowNotification(_ notification: Notification) {
        let userInfo = notification.userInfo //この中にキーボードの情報がある
        let keyboardSize = (userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let keyboardY = self.view.frame.size.height - keyboardSize.height //画面全体の高さ - キーボードの高さ = キーボードが被らない高さ
        let editingTextFieldY: CGFloat = (self.activeTextField?.frame.origin.y)!
        if editingTextFieldY > keyboardY - 60 {
            UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseIn, animations: {
                self.view.frame = CGRect(x: 0, y: self.view.frame.origin.y - (editingTextFieldY - (keyboardY - 60)), width: self.view.bounds.width, height: self.view.bounds.height)
            }, completion: nil)

        }
    }
ViewController.swift
    @objc private func handleKeyboardWillHideNotification(_ notification: Notification) {
        UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseIn, animations: {
            self.view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
        }, completion: nil)
    }

実装⑤ NotificationCenterの設定

最後にキーボードが呼ばれた時にメインの関数が呼ばれるように設定します。今回はNotificationCenterを用いて行いました。

ViewController.swift
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(self, selector: #selector(self.handleKeyboardWillShowNotification(_:)), name: .UIKeyboardWillShow, object: nil)
        notificationCenter.addObserver(self, selector: #selector(self.handleKeyboardWillHideNotification(_:)), name: .UIKeyboardWillHide, object: nil)
    }

ソースコード

参考までに作ったものをこちらに載せています。自由にダウンロードして使って見てください。

応用

このTextFieldは作るアプリによっては様々なところで利用する可能性があり、そう言った場合にいちいちすべてのViewControllerで実装するのは大変であり、冗長なものと言えるでしょう。
このような場合はその機能を備えたViewControllerを作成し、それを継承する形で利用するのが一番スマートだと思います。
参考までにこちらに実装してみた記事を載せているのでよかったらチェックしてみてください。
https://qiita.com/koooooo/items/ad20862cd486e0656d17

以上です。

慣れている方は十分くらいで終わると思います。この記事は初心者の方でも簡単にできるもので、アプリを作る上では結構大事になる部分だと思いますよー。