要件
UITableViewCell内にUITextFieldやUITextViewがあり、入力箇所とは別の部分をタップしたらキーボードを閉じたい。
extension
- 表示されているCellの中からファーストレスポンダを探すメソッドを生やす
extension UITableView {
func findFirstResponder() -> UIView? {
visibleCells.compactMap { cell in
cell.contentView.subviews.first { $0.isFirstResponder }
}.first
}
}
UIViewController
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
// ※1 タップジェスチャーを用意
private lazy var tapGesture = {
UITapGestureRecognizer(target: self, action: #selector(tappedGesture(gestureRecognizer:)))
}()
override func viewDidLoad() {
super.viewDidLoad()
observeNotifications()
}
// ※2 tapしたときの処理
@objc
func tappedGesture(gestureRecognizer: UITapGestureRecognizer) {
// ファーストレスポンダを探し、resignする
tableView.findFirstResponder()?.resignFirstResponder()
}
// キーボードの表示通知を監視
func observeNotifications() {
// ※3 キーボードが表示されたら Viewにジェスチャーを追加
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .current) { [weak self] _ in
guard let self = self else { return }
// tap gesture追加
self.view.addGestureRecognizer(self.tapGesture)
}
// ※4 キーボードが閉じたらジェスチャーを解除
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .current) { [weak self] _ in
guard let self = self else { return }
// tap gesture解除
self.view.removeGestureRecognizer(self.tapGesture)
}
}
}
drag もしくは scrollで閉じる
もしタップではなくドラッグもしくはスクロールしたときに閉じたい場合は、UITableViewの設定だけで可能。
tableView.keyboardDismissMode = .onDrag // or .interactive