【iOS】簡単にKeyboardを表示したときにTextFieldが隠れないようにする

この記事は ZOZOテクノロジーズ #1 Advent Calendar 2019 14日目の記事になります。
昨日の記事は @hkame さんによる「[Aurora->CloudSQLへMySQLレプリケーションはできるのか](https://qiita.com/hkame/items/9cff6117bc1763ac7810)」でした。

# はじめに
本記事はKeyboardを表示したときにTextFieldが隠れてしまわないようにするための実装についてです。
TextFieldが隠れないようにする実装のやり方は色々あると思いますが、本記事ではFrame計算などのない簡単な方法を紹介したいと思います。


# 結果
このような動きになります。
日本語キーボードにしてキーボードの高さが変わってもTextFieldの位置が変わっているのがいいですね。

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308861/785caf6e-31f7-1c01-2b30-0043416338d4.gif)


# 実装について

実装は単純で、キーボードが表示されたらScrollViewのcontentInset.bottomの値を調整します。

ポイントとしては、contentOffsetの調整ではなく、contentInsetの値を調整することです。
contentInsetの値を調整するメリットは、TextFieldの表示位置を気にしなくてもいいことです。
contentOffsetの値を変更する際に単純にキーボードの高さを足してしまうと、TextFieldの位置の制御をするためにキーボードがどの位置に表示されているかにより設定するcontentOffsetを求める計算が必要になります。

|contentOffset.yにキーボードの高さを足した場合|contentInset.bottomにキーボードの高さを足した場合|
|:---:|:---:|
|![Dec-14-2019 00-35-40.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308861/df91615c-8be4-3e29-3b6a-550993151649.gif)|![Dec-14-2019 00-27-48.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308861/3dcf1671-66f9-a896-716a-477079e9e927.gif)|


``` swift
import UIKit

class ViewController: UIViewController {
   
    @IBOutlet private weak var scrollView: UIScrollView!
    @IBOutlet private weak var nicknameTextField: UITextField!
    @IBOutlet private weak var birthdayTextField: UITextField!
    @IBOutlet private weak var submitButton: UIButton!
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidAppear(_:)), name: UIResponder.keyboardDidShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    @objc private func keyboardDidAppear(_ notification: Notification) {
        guard let keyboardFrame = (notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? NSValue)?.cgRectValue else { return }

        scrollView.contentInset.bottom = keyboardFrame.height
    }

    @objc private func keyboardWillDisappear(_ notification: Notification) {
        scrollView.contentInset.bottom = 0
    }
}
```

## キーボードの高さの監視タイミングについて
キーボードの表示、非表示のタイミングをそれぞれまとめてみました。


**キーボードの表示**

|keyboardWillAppear|keyboardDidShowNotification|
|:---:|:--:|
|![Dec-14-2019 00-43-12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308861/ad1292f8-ae69-b3b1-155e-94e92326c3f3.gif)|![Dec-14-2019 00-48-45.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308861/b78e22d4-ae9b-be7f-6baf-2e8ae6d9ea2d.gif)
|

**キーボードの非表示**

|keyboardWillAppear|keyboardDidShowNotification|
|:---:|:--:|
|![Dec-14-2019 00-49-38.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308861/2c46e812-6de1-9b2c-9fa6-e250c86adaef.gif)|![Dec-14-2019 00-46-07.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308861/cdeb492c-dd6c-250f-bae5-025d4011a88f.gif)
|

# まとめ
キーボードを表示した際にTextFieldを隠れないようにするには、scrollViewの`contentInset.bottom`の値を変更する実装がとても簡単です。
キーボードの非表示時監視タイミングを`keyboardDidShowNotification`にするとカクつくのでおすすめしません。


明日の記事は @r-tezuka さんによる公開予定です。どうぞお楽しみに。