iOS - 点击UITextField外部时收起键盘

492
我想知道如何让用户点击UITextField之外的区域时,键盘自动消失。

8
Dmitry给出了正确的答案。这不是一个手势问题,而是将第一响应者放弃的问题。Dmitry的答案也是Mark、Nutting和LeMarche在《Beginning iOS 4 Development》(http://www.amazon.com/dp/143023024X)第4章第83页中推荐的解决方案。 - jww
38个回答

791
你需要添加一个UITapGestureRecogniser并将其分配给视图,然后在其选择器上调用UITextField的resign first responder。
代码:
在viewDidLoad中:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];

[self.view addGestureRecognizer:tap];

In dismissKeyboard:


在 dismissKeyboard 函数中:
-(void)dismissKeyboard 
{
    [aTextField resignFirstResponder];
}

(其中aTextField是负责键盘的文本框)

Swift 3版本看起来就像这样

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard (_:)))
self.view.addGestureRecognizer(tapGesture)

对于dismissKeyboard

@objc func dismissKeyboard (_ sender: UITapGestureRecognizer) {
    aTextField.resignFirstResponder()
}

7
这种方法可以解决问题,但它也会禁用或使导航栏按钮无法点击。那么有没有解决这个问题的方法? - Parth Bhatt
145
我认为比[aTextField resignFirstResponder]更好的方法是[self.view endEditing:YES];,它不需要引用文本字段,并且适用于多个文本字段。 - Julian
90
不需要定义任何方法,只需一行代码即可实现:[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self.view action:@selector(endEditing:)]]; - Subhas
12
我添加了 [tap setCancelsTouchesInView:NO];,这是根据 @qiaoyi 的建议;我曾经遇到一个表格没有响应行选择的问题。五年后,希望这能帮助其他人解决类似问题。 - Tom Howard
12
简洁的一行代码:self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:)))) - Malfunction
显示剩余10条评论

181

我把几个答案搭配起来了。

viewDidLoad:期间初始化一个实例变量(ivar)。

UIGestureRecognizer *tapper;

- (void)viewDidLoad
{
    [super viewDidLoad];
    tapper = [[UITapGestureRecognizer alloc]
                initWithTarget:self action:@selector(handleSingleTap:)];
    tapper.cancelsTouchesInView = NO;
    [self.view addGestureRecognizer:tapper];
}

取消当前正在编辑的内容:

- (void)handleSingleTap:(UITapGestureRecognizer *) sender
{
    [self.view endEditing:YES];
}

太棒了,它可以在UITableView上运行!它救了我的一天!另外,我会使用[UITextField resignFirstResponder]而不是[UIView endEditing:],因为我有更多的UITextField,即使新的UITextField可见,endEditing也会给出错误的滚动位置。 - Dr.Luiji
1
完全错误,因为UITapGestureRecognizer从未添加到视图中! - user246672
1
这里 cancelsTouchesInView 的作用是什么? - Adam Johns
4
如果您不在此处添加cancelsTouchesInView = false,则无法选择视图中的其他类型项目。 您的点击将被手势识别器拦截。 - HalR

106

看这里,这将是最简单的方法来做到这一点,

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
      [self.view endEditing:YES];// this will do the trick
}

或者

这个库将处理包括滚动条自动滚动,轻触空格键隐藏键盘等功能...

https://github.com/michaeltyson/TPKeyboardAvoiding


@Ramesh 是的,它可以,但不是这种方式。你需要从UITableView创建一个子类,在该类中实现touchesBegan方法,然后调用endEditing方法。它有效!不要忘记在nib中为您的表设置新创建的类。 - Prasad De Zoysa
3
用户在视图上点击其他控件时,它不会隐藏键盘。例如,我在UIView上有一个UIButton和一个UITextField。当我点击UITextField,然后再点击按钮时,键盘并没有被隐藏。 - Jacob Dam
2
@JacobDam 你说得对。目标是在aTextField之外发生任何事情时,使用resignfirstresponder隐藏键盘。 - user246672

90

我发现有些人在使用UITapGestureRecognizer方法时遇到了问题。 我实现这个功能的最简单方法是在@Jensen2k的答案中只添加一行代码,同时保留我的现有按钮的点击行为:

[tap setCancelsTouchesInView:NO];

这使得我的现有按钮仍然可以正常工作,而无需使用 @Dmitry Sitnikov 的方法。

在此处阅读有关该property的信息(搜索 CancelsTouchesInView):UIGestureRecognizer Class Reference

我不确定它如何与滚动条一起工作,因为我看到有些人遇到了问题,但希望其他人也可能遇到我遇到的相同情况。


3
我还想补充一点,对于那些在视图背景上使用 UIImageView 的人,请添加 [imageView setUserInteractionEnabled:NO]; 并且您可以“穿透”它,这样就可以使该方法起作用。 - Paul Peelen

56

更好的方法是将您的 UIView 实例化为 UIControl(在界面构建器中),然后将它们的 TouchUpInside 事件连接到 dismissKeyboard 方法。这个 IBAction 方法看起来像:

- (IBAction)dismissKeyboard:(id)sender {
    [aTextBox resignFirstResponder];
}

1
谢谢!这对我很有用,其他解决方案都不行。(UITapGestureRecognizer干扰了视图内部按钮的点击)。touchesEnded无法工作,因为有一个UIScrollView干扰了响应链。 - jlstrecker
1
这个很好用,但必须添加到您想要取消键盘的任何内容中。有没有一种方法可以在点击其他任何东西时自动使文本框放弃第一响应者? - Isaac Overacker
4
不需要将 UIView 变为 UIControl。请确保 UIView 开启了用户交互功能。 - Sofi Software LLC
1
@SofiSoftwareLLC 您的建议对我没有起作用。即使启用了用户交互,我也不得不将其设置为UIControl。 - three-cups
1
使用Storyboard,我将UIView更改为UIControl(如果我创建了一个UIView子类,则会选择它)。它运行良好,我没有遇到任何问题。iOS8。 - ToddB
显示剩余3条评论

49

Swift 4

viewDidLoad中使用以下扩展方法来设置您的UIViewController

override func viewDidLoad() {
    super.viewDidLoad()
    self.setupHideKeyboardOnTap()
}

即使点击 NavigationBar,键盘也会被关闭。

import UIKit
extension UIViewController {
    /// Call this once to dismiss open keyboards by tapping anywhere in the view controller
    func setupHideKeyboardOnTap() {
        self.view.addGestureRecognizer(self.endEditingRecognizer())
        self.navigationController?.navigationBar.addGestureRecognizer(self.endEditingRecognizer())
    }

    /// Dismisses the keyboard from self.view
    private func endEditingRecognizer() -> UIGestureRecognizer {
        let tap = UITapGestureRecognizer(target: self.view, action: #selector(self.view.endEditing(_:)))
        tap.cancelsTouchesInView = false
        return tap
    }
}

3
兄弟,你太牛了!!这个答案非常完美,效果真的很好,非常感谢。 - user5683940
1
谢谢!这拯救了我的一天。 - Hitesh Surani

28

在 Swift 版本中,这个功能需要与其他元素(如 UIButton 或另一个 UITextField)结合使用:

override func viewDidLoad() {
    super.viewDidLoad()

    let tapper = UITapGestureRecognizer(target: self, action:#selector(endEditing))
    tapper.cancelsTouchesInView = false
    view.addGestureRecognizer(tapper)
}

1
目标应该是 self 而不是 self.view - Bhavin Bhadani
1
目标应该是self.view。否则,以上代码将崩溃。 - Naga Mallesh Maddali
“cancelsTouchesInView”是一个很方便的属性。谢谢。 - JonSlowCN
老习惯难改。这个分号在这里干嘛?;) - Alexandre G.
@AlexandreG。确实,特别是因为我通常编写 c# 代码。FYI那个分号是语法允许的,只是不必要的。 - Rob
如果您的操作选择器方法在当前VC的视图Swift文件中,则目标应该是self.view。大多数情况下,操作选择器方法将在VC本身中,因此目标只需为self。希望这能帮助到某些人。 :) - purefusion

17

这样怎么样:我知道这是一篇旧帖子,但它可能会对某些人有所帮助 :)

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {  
    NSArray *subviews = [self.view subviews];
    for (id objects in subviews) {
        if ([objects isKindOfClass:[UITextField class]]) {
            UITextField *theTextField = objects;
            if ([objects isFirstResponder]) {
                [theTextField resignFirstResponder];
            }
        } 
    }
}

我没有检查UITextField,所以它适用于任何输入类型。看不到任何问题。 - Frank

17

这是一个不错的通用解决方案:

Objective-C:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];    
}

迅捷:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    self.view.endEditing(true)
}

基于 @icodebuster 的解决方案:https://dev59.com/TWMl5IYBdhLWcg3wBzDy#18756253


15

Swift 4 单行代码

view.addGestureRecognizer(UITapGestureRecognizer(target: view, action: #selector(UIView.endEditing(_:))))

代码很好,但这个禁用了删除功能(-)。 - schellingerht
你是个天才! - Abhishek Bedi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接