Introduction: Why doesn't the keyboard close by itself?
\nHello, fellow developer! If you've ever written a login form, search bar, or messenger on iOS, you've probably encountered this situation: the user has entered text, but the keyboard stubbornly stays on the screen. The "Done" button wasn't pressed, the user taps an empty space, but nothing happens. A classic.
\n\nThis is one of the most popular topics on Stack Overflow, where the question "Close iOS Keyboard by touching anywhere using Swift" has thousands of views. The problem isn't that it's difficult to do. The problem is that beginners (and not only) often choose incorrect or "dirty" methods. Let's break down the top 3 mistakes, and then look at three correct, working solutions.
\n\nToday we're talking about Swift and UIKit. If you use SwiftUI — take a look too, the principles are similar.
\n\nMistake #1: "Adding TapGesture to everything"
\nThe most common mistake is adding a UITapGestureRecognizer to a UIView, but forgetting to disable cancelsTouchesInView. As a result, buttons and tables stop responding to taps. The user taps the "Send" button, but the keyboard dismissal triggers instead of form submission.
Example of incorrect code:
\noverride func viewDidLoad() {\n super.viewDidLoad()\n let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))\n view.addGestureRecognizer(tap)\n}\n\n@objc func dismissKeyboard() {\n view.endEditing(true)\n}\n\nAt first glance — it looks fine. But in practice, if you have a UITableView or UIButton, their taps can be "swallowed" by this gesture. This is especially noticeable when you add such a gesture to a scrollView.
How to fix:
\nAdd the line tap.cancelsTouchesInView = false. This will allow other interface elements to receive touch events.
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))\ntap.cancelsTouchesInView = false\nview.addGestureRecognizer(tap)\n\nBut even this is not an ideal solution if you have a complex interface.
\n\nMistake #2: "Tapping empty space breaks the table"
\nThe second popular problem is incorrect interaction with UIScrollView or UITableView. If you add a UITapGestureRecognizer to a view that contains a table, tapping a cell might trigger both the gesture and the didSelectRow method simultaneously. Or, even worse, the gesture will intercept the touch, and the cell won't be highlighted.
Solution: use UIGestureRecognizerDelegate
\nImplement the gestureRecognizer(_:shouldReceive:) method and check whether the tap was on a text field or another element. If the touch landed on a UITextField or UITextView — don't block the gesture.
extension ViewController: UIGestureRecognizerDelegate {\n func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {\n // Don't intercept touches if they landed on a text field\n if touch.view is UITextField || touch.view is UITextView {\n return false\n }\n return true\n }\n}\n\nNow the gesture will only trigger when tapping empty areas, while text fields remain interactive.
\n\nMistake #3: "Forgetting about the keyboard return key"
\nMany developers implement dismissal by tap, but forget about the "Return" (Enter) button on the keyboard. The user might press "Done" and expect the keyboard to close. If this isn't handled — you'll get a negative UX.
\n\nHow to fix:
\nConform to the UITextFieldDelegate protocol and implement the textFieldShouldReturn method:
class View