Как закрыть клавиатуру iOS по нажатию в любом месте экрана (Swift)
Решение: корректная настройка UITapGestureRecognizer для скрытия клавиатуры
Ваш код в целом правильный, но есть несколько нюансов, которые могут помешать работе. Самая частая проблема — это то, что UITapGestureRecognizer может конфликтовать с другими жестами (например, с прокруткой в UIScrollView или UITableView). Но в простом случае с формой проблема обычно в другом: распознаватель жестов может не срабатывать, если он не настроен правильно для взаимодействия с другими элементами.
Вот рабочий и самый распространённый подход:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupHideKeyboardOnTap()
}
private func setupHideKeyboardOnTap() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideKeyboard))
tapGesture.cancelsTouchesInView = false
view.addGestureRecognizer(tapGesture)
}
@objc private func hideKeyboard() {
view.endEditing(true)
}
}
Ключевой момент: свойство cancelsTouchesInView
Обратите внимание на строку tapGesture.cancelsTouchesInView = false. По умолчанию это свойство равно true. Когда вы нажимаете на пустое место, распознаватель жестов "перехватывает" касание и не передаёт его дальше другим элементам (например, кнопкам или другим text field). Установка false позволяет другим элементам интерфейса получать касания после того, как распознаватель обработал жест. Это решает проблему, когда нажатие на фон не срабатывает.
Дополнительные рекомендации:
- Работа с UIScrollView или UITableView: Если ваша форма находится внутри
UIScrollView, добавьте распознаватель на сам scroll view, а не на главное view. Или используйте более продвинутый подход с делегатомUIGestureRecognizerDelegate. - Проверка, является ли нажатие на text field: Иногда нужно, чтобы клавиатура не скрывалась, когда пользователь переключается между text field. Для этого можно добавить проверку:
@objc private func hideKeyboard(_ sender: UITapGestureRecognizer) {
let location = sender.location(in: view)
if let hitView = view.hitTest(location, with: nil), hitView is UITextField {
return // не скрываем клавиатуру, если нажали на text field
}
view.endEditing(true)
}
- Альтернативный метод: Используйте
resignFirstResponder()для конкретного text field, если у вас только одно поле ввода:
@objc private func hideKeyboard() {
myTextField.resignFirstResponder()
}
Почему это работает?
Метод view.endEditing(true) рекурсивно проходит по всем subviews и вызывает у каждого resignFirstResponder(). Это гарантирует, что любой активный text field или text view потеряет фокус, и клавиатура закроется.
Это решение подходит для 99% случаев и считается стандартом в iOS разработке на Swift.
<<Альтернативный подход: расширение (extension) для UIViewController
Если вы используете этот функционал во многих контроллерах, удобно вынести его в расширение. Это уменьшит дублирование кода и сделает проект чище.
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
@objc private func dismissKeyboard() {
view.endEditing(true)
}
}
Теперь в любом вашем контроллере достаточно вызвать один метод:
override func viewDidLoad() {
super.viewDidLoad()
hideKeyboardWhenTappedAround()
}
Дополнение: использование UIResponder
Ещё один способ — использовать цепочку респондеров. Вы можете создать кастомный метод, который будет вызывать resignFirstResponder у текущего активного элемента через UIApplication.shared.sendAction:
@objc private func dismissKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
Этот метод отправляет действие resignFirstResponder по всей цепочке респондеров, что гарантированно скроет клавиатуру. Однако первый подход с view.endEditing(true) более читаемый и предпочтительный.
Выбирайте тот вариант, который лучше подходит под архитектуру вашего приложения.
Ответов пока нет.
Войдите чтобы оставить ответ