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

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

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

10

我认为最简单(也是最好的)方法是创建一个子类全局视图,并使用hitTest:withEvent方法监听任何触摸事件。键盘上的触摸不会被注册,因此只有当您在其他地方触摸/滚动/划动/捏合...时,才会调用hitTest:withEvent方法,然后调用[self endEditing:YES]

这比使用touchesBegan更好,因为如果您单击视图顶部的按钮,则不会调用touchesBegan。它比UITapGestureRecognizer更好,例如无法识别滚动手势。它也比使用暗屏幕更好,因为在复杂和动态的用户界面中,您无法将暗屏幕放置到每个位置。此外,它不会阻止其他操作,您不需要两次轻敲才能选择外部的按钮(例如使用UIPopover时需要)。

此外,它比调用[textField resignFirstResponder]更好,因为屏幕上可能有许多文本字段,所以这适用于所有文本字段。


不幸的是,这似乎会干扰UISearchBar中的“X”清除文本的功能。 - huggie
1
这种方法存在一些问题。例如,您无法在不失去文本字段焦点的情况下滚动ScrollView。对于更复杂的场景不建议使用...个人而言,我更喜欢Dmitry的UIControl版本,也许可以通过Sofi Software的评论进行扩展。 - katzenhut
一个滚动的例子是在电子邮件应用程序中,当您在搜索栏中输入内容并滚动邮件列表时,键盘会被隐藏。 - Enzo Tran
这是最好的方法,也适用于我的其他项目。 - Chandramani

9

7
如果视图在UIScrollView中嵌入,那么您可以使用以下方法:
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

前者将在滚动表视图时使键盘离开屏幕,后者将像原生消息应用程序一样隐藏键盘。

请注意,这些功能仅适用于iOS 7.0或更高版本。


6
您可以使用XCode 6及以上版本中的Storyboard来完成此操作:


创建隐藏键盘的操作

将以下内容添加到您的ViewController使用的类的头文件中:

@interface TimeDelayViewController : UIViewController <UITextFieldDelegate>

- (IBAction)dissmissKeyboardOnTap:(id)sender;

@end

然后将以下内容添加到同一ViewController的实现文件中:

- (IBAction)dissmissKeyboardOnTap:(id)sender{
    [[self view]endEditing:YES];
}

这将成为您故事板场景(即ViewController)中的“接收操作”之一:

enter image description here


将操作与用户事件连接起来

现在,您需要将此操作连接到触发键盘的用户手势上。

重要提示 - 您需要将故事板中包含的 'UIView' 转换为 'UIControl',以便它可以接收事件。从您的视图控制器场景层次结构中选择视图:

enter image description here

...并更改它的类:

enter image description here

现在,从您场景旁边的小圆圈处拖动“接收操作”,拖到场景的“空白”部分(实际上是将“接收操作”拖到UIControl上)。然后,您将看到一系列事件可供选择,可以将您的操作连接到其中之一。

enter image description here

选择“touch up inside”选项。现在,您已经将所创建的IBAction钩到了触发键盘关闭的用户操作上。当用户点击键盘时,它将被隐藏。
(注意:要将操作连接到事件上,您还可以直接从接收到的操作拖动到视图控制器层次结构中的UIControl上。在层次结构中显示为“Control”。)

感谢您提供的解决方案和详细的解释。对我非常有帮助。 - Yongxiang Ruan

5
如果我理解正确,您想在点击textfield外部时取消键盘,但是您没有textfield的引用。
请尝试以下方法;
  • Take global textField, lets call it reftextField
  • Now in textFieldDidBeginEditing set referenced text field to

    - (void) textFieldDidBeginEditing:(UITextField *)textField{
        reftextField = textField;
    }
    
  • Now you can happily use on any button clock, (adding a transparent button on begin editing recomended)

    - (void)dismissKeyboard {
          [reftextField resignFirstResponder];
    }
    
  • Or for resigning done button try this.

    //for resigning on done button    
    - (BOOL) textFieldShouldReturn:(UITextField *)textField{
        [textField resignFirstResponder];
        return YES;
    }
    

5
在Swift 5中,您可以使用以下代码在文本框外部取消显示键盘。
override func viewDidLoad() {
    // ... code

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

@objc func dismissKeyboard(_ sender: UITapGestureRecognizer) {
    self.view.endEditing(true)
}

1
如果您的视图中也包含tableViewscollectionViews,请将以下内容作为tapGesture配置的一部分包括进去:tapGesture.cancelsTouchesInView = false - cro

4

在此补充一下如何通过触摸屏幕外部来关闭键盘的方法。

viewDidLoad:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleTap];

无处不在:

-(void)handleSingleTap:(UITapGestureRecognizer *)sender{
    [textFieldName resignFirstResponder];
    puts("Dismissed the keyboard");
}

4

Objective-C:

将下面的代码添加到您的ViewController.m 文件中:

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

Swift:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
}

1
太棒了!我喜欢这个答案。精确而且尽量简洁。何必费心设置手势识别器和所有其他样板代码呢?这应该是被采纳的答案。 - Adrian Salazar

3

您可以为UiView创建类别,并如下覆盖touchesBegan方法。

对我来说,它的工作很好。这是解决此问题的集中化解决方案。

#import "UIView+Keyboard.h"
@implementation UIView(Keyboard)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.window endEditing:true];
    [super touchesBegan:touches withEvent:event];
}
@end

3

@Jensen2k的答案的Swift版本:

let gestureRecognizer : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: "dismissKeyboard")
self.view.addGestureRecognizer(gestureRecognizer)

func dismissKeyboard() {
    aTextField.resignFirstResponder()
}

一句话简述

self.view.addTapGesture(UITapGestureRecognizer.init(target: self, action: "endEditing:"))

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