【iOS】キーボード周りのNotificationをprotocolでデフォルト実装する


キーボードの表示・非表示でViewの変更などをする際に、ViewControllerごとにaddObserverやremoveObserverを書いたりするのをなんとか減らしたいと思い、下記のような実装をしてみました。

protocol KeyboardObservable: class {
    var keyboardObservers: [Any] { get set }
    func keyboardWillShow(_ notification: Notification)
    func keyboardDidShow(_ notification: Notification)
    func keyboardWillHide(_ notification: Notification)
    func keyboardDidHide(_ notification: Notification)
    func addKeyboardObservers()
    func removeKeyboardObservers()
}

extension KeyboardObservable {
    func addKeyboardObservers() {
        keyboardObservers = [
            (.UIKeyboardWillShow, keyboardWillShow(_:)),
            (.UIKeyboardDidShow, keyboardDidShow(_:)),
            (.UIKeyboardWillHide, keyboardWillHide(_:)),
            (.UIKeyboardDidHide, keyboardDidHide(_:))
        ].map { NotificationCenter.default.addObserver(forName: $0, object: nil, queue: .main, using: $1) }
    }

    func removeKeyboardObservers() {
        keyboardObservers.forEach { NotificationCenter.default.removeObserver($0) }
        keyboardObservers.removeAll()
    }
}
  • keyboardWillShow(_:)
  • keyboardDidShow(_:)
  • keyboardWillHide(_:)
  • keyboardDidHide(_:)

はprotocolによって実装が強制されるので、タイポなどによってactionが呼ばれないというミスが減ります。

class ViewController: UIViewController, KeyboardObservable {

    var keyboardObservers: [Any] = []

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        addKeyboardObservers()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        removeKeyboardObservers()
    }

    func keyboardWillShow(_ notification: Notification) {
        //キーボードが表示される前の処理
    }

    func keyboardDidShow(_ notification: Notification) {
        //キーボードが表示された後の処理
    }

    func keyboardWillHide(_ notification: Notification) {
        //キーボードが非表示にされる前の処理
    }

    func keyboardDidHide(_ notification: Notification) {
        //キーボードが非表示にされた後の処理
    }
}

上記のようにKeyboardObservableを採用することで、キーボードのNotificationをハンドリングしたいViewControllerだけで呼び出しが可能になります。