引言:为什么键盘不会自动关闭?
\n你好,开发者同行!如果你曾经在iOS上编写过登录表单、搜索栏或即时通讯应用,那么你一定遇到过这种情况:用户输入了文本,但键盘却固执地停留在屏幕上。用户没有按下“完成”按钮,而是点击空白区域,但什么也没有发生。经典问题。
\n\n这是Stack Overflow上最热门的话题之一,其中问题"使用Swift通过任意位置点击关闭iOS键盘"获得了数千次浏览。问题不在于实现困难,而在于新手(甚至不止新手)常常选择错误或“不优雅”的方法。让我们先分析3个最常见的错误,然后再看三种正确且实用的解决方案。
\n\n今天我们讨论的是Swift和UIKit。如果你使用SwiftUI,也请参考一下,原理是相似的。
\n\n错误#1:“在所有地方添加点击手势”
\n最常见的错误是在UIView上添加UITapGestureRecognizer,但忘记禁用cancelsTouchesInView。结果导致按钮和表格无法响应点击。用户点击“发送”按钮,但触发的是键盘关闭,而不是表单提交。
错误代码示例:
\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\n乍一看,似乎没问题。但实际上,如果你有UITableView或UIButton,它们的点击可能会被这个手势“吞掉”。当你将这样的手势添加到scrollView上时,这一点尤其明显。
如何修复:
\n添加一行代码tap.cancelsTouchesInView = false。这将允许其他界面元素接收触摸事件。
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))\ntap.cancelsTouchesInView = false\nview.addGestureRecognizer(tap)\n\n但即使这样,如果你的界面复杂,这也不是一个完美的解决方案。
\n\n错误#2:“点击空白区域破坏表格”
\n第二个常见问题是与UIScrollView或UITableView的错误交互。如果你在包含表格的view上添加UITapGestureRecognizer,那么点击单元格时,手势和didSelectRow方法可能会同时触发。更糟糕的是,手势可能会拦截触摸,导致单元格无法被选中。
解决方案:使用UIGestureRecognizerDelegate
\n实现gestureRecognizer(_:shouldReceive:)方法,并检查点击是否发生在文本字段或其他元素上。如果触摸发生在UITextField或UITextView上,则不要拦截手势。
extension ViewController: UIGestureRecognizerDelegate {\n func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {\n // 如果触摸发生在文本字段上,则不拦截\n if touch.view is UITextField || touch.view is UITextView {\n return false\n }\n return true\n }\n}\n\n现在,手势只会在点击空白区域时触发,而文本字段仍保持可交互状态。
\n\n错误#3:“忘记处理键盘返回键”
\n许多开发者实现了点击关闭键盘,但忘记了键盘上的“Return”(回车)按钮。用户可能会按下“完成”并期望键盘关闭。如果不这样做,将会带来糟糕的用户体验。
\n\n如何修复:
\n遵循UITextFieldDelegate协议并实现textFieldShouldReturn方法:
class View