iOS - 在UITextField外部触摸时关闭键盘

时间:2011-03-15 00:31:22

标签: ios cocoa-touch uitextfield uikit

我想知道当用户触摸UITextField之外时如何使键盘消失。

38 个答案:

答案 0 :(得分:733)

您需要添加UITapGestureRecogniser并将其分配给视图,然后在其选择器上的UITextField上调用resign first responder。

代码:

在viewDidLoad

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)];

[self.view addGestureRecognizer:tap];

在dismissKeyboard:

-(void)dismissKeyboard 
{
    [aTextField resignFirstResponder];
}

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

Swift 3 版本看起来像那样

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

适用于dismissKeyboard

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

答案 1 :(得分:170)

我捣乱了几个答案。

使用在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];
}

答案 2 :(得分:100)

检查一下,这将是最简单的方法,

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

或者

此库将处理包括滚动条自动滚动,点击空间以隐藏键盘等...

https://github.com/michaeltyson/TPKeyboardAvoiding

答案 3 :(得分:84)

我发现有些人在使用UITapGestureRecognizer方法时遇到了问题。我完成此功能的最简单方法是在保持现有按钮的点击行为不变的情况下,只添加一行@ Jensen2k的答案:

[tap setCancelsTouchesInView:NO];

这允许我现有的按钮仍然可以使用@Dmitry Sitnikov的方法。

在此处了解property(搜索CancelsTouchesInView):UIGestureRecognizer Class Reference

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

答案 4 :(得分:55)

最好让UIView UIControl的实例(在界面构建器中),然后将他们的TouchUpInside事件连接到dismissKeyboard方法。这个IBAction方法如下所示:

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

答案 5 :(得分:28)

Swift版本,它与其他元素(例如UIButton或其他UITextField)结合使用:

override func viewDidLoad() {
    super.viewDidLoad()

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

答案 6 :(得分: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];
            }
        } 
    }
}

答案 7 :(得分:17)

Swift 4

使用此扩展程序设置UIViewController,例如viewDidLoad

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
    }
}

答案 8 :(得分:14)

这是一个很好的通用解决方案:

目标-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://stackoverflow.com/a/18756253/417652

答案 9 :(得分:10)

我认为最简单(也是最好)的方法是对全局视图进行子类化,并使用hitTest:withEvent方法来监听任何触摸。键盘上的触摸未注册,因此仅当您在其他地方触摸/滚动/滑动/捏合... 时,才会调用hitTest:withEvent,然后调用[self endEditing:YES]

这比使用touchesBegan更好,因为如果单击视图顶部的按钮,则不会调用touchesBegan。例如,它比无法识别滚动手势的UITapGestureRecognizer更好。它也比使用昏暗的屏幕更好,因为在复杂和动态的用户界面中,你无法在任何地方放置昏暗的屏幕。此外,它不会阻止其他操作,您无需点击两次以选择外部按钮(例如UIPopover)。

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

答案 10 :(得分:7)

快速4个单排纸

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

答案 11 :(得分:6)

这一定是通过触摸外面隐藏键盘的最简单方法:

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

(来自How to dismiss keyboard when user tap other area outside textfield?

答案 12 :(得分: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 ,以便它可以接收事件。从View Controller Scene层次结构中选择视图:

enter image description here

...并更改其班级:

enter image description here

现在从场景的“已接收动作”旁边的小圆圈拖到场景的“空”部分(实际上是将“已接收动作”拖动到UIControl)。您将看到一系列可以将您的操作连接到的事件:

enter image description here

选择“内部修饰”选项。您现在已将您创建的IBAction挂钩到用户触摸键盘的操作。当用户轻敲键盘时,它现在将被隐藏。

(注意:要将操作挂钩到事件,您还可以将接收到的操作直接拖到View Controllers层次结构中的UIControl上。它在层次结构中显示为“Control”。)

答案 13 :(得分:5)

如果我说得对,你想要在textfield之外点击键盘诡计,但你没有引用textfield

试试这个;

  • 使用全局textField,我们称之为reftextField
  • 现在textFieldDidBeginEditing将参考文本字段设置为

    - (void) textFieldDidBeginEditing:(UITextField *)textField{
        reftextField = textField;
    }
    
  • 现在您可以愉快地使用任何按钮时钟,(在开始编辑时添加透明按钮推荐)

    - (void)dismissKeyboard {
          [reftextField resignFirstResponder];
    }
    
  • 或者对于辞职完成按钮试试这个。

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

答案 14 :(得分:5)

如果视图完全嵌入UIScrollView,那么您可以使用以下内容:

tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

前者会在滚动表格视图时将键盘设置为关闭屏幕,而后者会像股票消息应用程序一样隐藏键盘。

  

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

答案 15 :(得分:3)

只是在这里添加我的版本如何在外部触摸时解除键盘。

viewDidLoad中:

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

Anywhere的:

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

答案 16 :(得分:3)

@ Jensen2k的答案的快速版本:

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:"))

答案 17 :(得分:3)

您可以为UiView创建类别并覆盖touchesBegan meathod,如下所示。

它对我来说很好。它是这个问题的集中解决方案。

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

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

答案 18 :(得分:3)

这里有很多关于使用UITapGestureRecognizer的好答案 - 所有这些都会打破UITextField的清除(X)按钮。解决方案是通过其委托来抑制手势识别器:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    BOOL touchViewIsButton = [touch.view isKindOfClass:[UIButton class]];
    BOOL touchSuperviewIsTextField = [[touch.view superview] isKindOfClass:[UITextField class]];
    return !(touchViewIsButton && touchSuperviewIsTextField);
}

这不是最强大的解决方案,但它对我有用。

答案 19 :(得分:2)

最简单最短的方法之一是将此代码添加到viewDidLoad

[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc]
                                     initWithTarget:self.view
                                     action:@selector(endEditing:)]];

答案 20 :(得分:2)

我使用巴里的例子来进行新的开发。它工作得很好!但我必须稍微改变,只需要为正在编辑的文本字段解除键盘。

所以,我向Barry添加了以下内容:

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    _textBeingEdited = textField;
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
    _textBeingEdited = nil;
}

另外,我更改了hideKeyboard方法如下:

- (IBAction)hideKeyboard:(id)sender
{
    // Just call resignFirstResponder on all UITextFields and UITextViews in this VC
    // Why? Because it works and checking which one was last active gets messy.
    //UITextField * tf = (UITextField *) sender;
    [_textBeingEdited resignFirstResponder];
}

答案 21 :(得分:2)

我在这里尝试了许多回复并没有运气。即使我将手势识别器的UIButtons属性设置为NO,我的点击手势识别器始终会导致我的cancelsTouchesInView无法响应。

这最终解决了这个问题:

有一个ivar:

UITapGestureRecognizer *_keyboardDismissGestureRecognizer;

当文本字段开始编辑时,请设置手势识别器:

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    if(_keyboardDismissGestureRecognizer == nil)
    {
        _keyboardDismissGestureRecognizer = [[[UITapGestureRecognizer alloc]
                                       initWithTarget:self
                                       action:@selector(dismissKeyboard)] autorelease];
        _keyboardDismissGestureRecognizer.cancelsTouchesInView = NO;

        [self.view addGestureRecognizer:_keyboardDismissGestureRecognizer];
    }
}

然后诀窍在于如何设置dismissKeyboard方法:

- (void) dismissKeyboard
{
    [self performSelector:@selector(dismissKeyboardSelector) withObject:nil afterDelay:0.01];
}

- (void) dismissKeyboardSelector
{
    [self.view endEditing:YES];

    [self.view removeGestureRecognizer:_keyboardDismissGestureRecognizer];
    _keyboardDismissGestureRecognizer = nil;
}

我想有一些关于从触摸处理执行堆栈中获取dismissKeyboardSelector执行的东西......

答案 22 :(得分:1)

将消息resignFirstResponder发送到将其放在那里的文本字段。请see this post了解更多信息。

答案 23 :(得分:1)

ViewController.m 文件中添加此代码:

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

答案 24 :(得分:1)

您可以使用UITapGestureRecongnizer方法通过单击UITextField外部来解除键盘。通过使用此方法,只要用户在UITextField外部单击,键盘就会被解除。以下是使用它的代码段。

 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
                                   initWithTarget:self
                                   action:@selector(dismissk)];

    [self.view addGestureRecognizer:tap];


//Method
- (void) dismissk
{
    [abctextfield resignFirstResponder];
    [deftextfield resignFirstResponder];

}

答案 25 :(得分:1)

- (void)viewDidLoad
{
    [super viewDidLoad]; 

UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
                                                          initWithTarget:self
                                                          action:@selector(handleSingleTap:)];
    [singleTapGestureRecognizer setNumberOfTapsRequired:1];
    [singleTapGestureRecognizer requireGestureRecognizerToFail:singleTapGestureRecognizer];

    [self.view addGestureRecognizer:singleTapGestureRecognizer];
}

- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
    [self.view endEditing:YES];
    [textField resignFirstResponder];
    [scrollView setContentOffset:CGPointMake(0, -40) animated:YES];

}

答案 26 :(得分:1)

在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)
}

答案 27 :(得分:1)

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    if let touch = touches.first{
     view.endEditing(true)

     }
}

答案 28 :(得分:1)

在这种情况下,可以使用 ScrollView 并添加到ScrollView中的TextField,我想点击ScrollView然后查看然后关闭键盘。为了以防万一,我尝试创建示例代码。像这样,

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap(_:)))
        view.addGestureRecognizer(tapGesture)
        // Do any additional setup after loading the view, typically from a nib.
    }
    func tap(gesture: UITapGestureRecognizer) {
        textField.resignFirstResponder()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

你的故事板看看就像。

enter image description here

答案 29 :(得分:1)

  • 在视图中设置文本字段委托加载:

    override func viewDidLoad() 
    {
      super.viewDidLoad()
      self.userText.delegate = self
    }
    
  • 添加此功能:

    func textFieldShouldReturn(userText: UITextField!) -> Bool 
    {
     userText.resignFirstResponder()
     return true;
    }
    

答案 30 :(得分:1)

对于那些在Swift中苦苦挣扎的人。这是Jensen2k接受的答案,但在Swift中。

Swift 2.3

    override func viewDidLoad() {
        //.....

        let viewTapGestureRec = UITapGestureRecognizer(target: self, action: #selector(handleViewTap(_:)))
        //this line is important
        viewTapGestureRec.cancelsTouchesInView = false
        self.view.addGestureRecognizer(viewTapGestureRec)

         //.....
    }

    func handleViewTap(recognizer: UIGestureRecognizer) {
        myTextField.resignFirstResponder()
    }

答案 31 :(得分:1)

这可行

在这个例子中,aTextField是唯一的UITextField ....如果还有其他人或UITextViews,还有更多工作要做。

// YourViewController.h
// ...
@interface YourViewController : UIViewController /* some subclass of UIViewController */ <UITextFieldDelegate> // <-- add this protocol
// ...
@end

// YourViewController.m

@interface YourViewController ()
@property (nonatomic, strong, readonly) UITapGestureRecognizer *singleTapRecognizer;
@end
// ...

@implementation
@synthesize singleTapRecognizer = _singleTapRecognizer;
// ...

- (void)viewDidLoad
{
    [super viewDidLoad];
    // your other init code here
    [self.view addGestureRecognizer:self.singleTapRecognizer];

{

- (UITapGestureRecognizer *)singleTapRecognizer
{
    if (nil == _singleTapRecognizer) {
        _singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapToDismissKeyboard:)];
        _singleTapRecognizer.cancelsTouchesInView = NO; // absolutely required, otherwise "tap" eats events.
    }
    return _singleTapRecognizer;
}

// Something inside this VC's view was tapped (except the navbar/toolbar)
- (void)singleTapToDismissKeyboard:(UITapGestureRecognizer *)sender
{
    NSLog(@"singleTap");
    [self hideKeyboard:sender];
}

// When the "Return" key is pressed on the on-screen keyboard, hide the keyboard.
// for protocol UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField*)textField
{
    NSLog(@"Return pressed");
    [self hideKeyboard:textField];
    return YES;
}

- (IBAction)hideKeyboard:(id)sender
{
    // Just call resignFirstResponder on all UITextFields and UITextViews in this VC
    // Why? Because it works and checking which one was last active gets messy.
    [aTextField resignFirstResponder];
    NSLog(@"keyboard hidden");
}

答案 32 :(得分:0)

重要的是一件事...

向视图添加手势识别可以使子视图覆盖它。 因此,仅执行一项操作。 如果要执行通过超级视图和子视图识别多个动作... 您必须使用

array1 = [{
    "orgId": 101,
    "orgGN": "ABC",
    "dId": 494,
    "name": "Test1",
  },
  {
    "orgId": 102,
    "orgGN": "ABC",
    "dId": 442,
    "name": "Test2",
  },
  {
    "orgId": 103,
    "orgGN": "ASR",
    "dId": 494,
    "name": "Test3",
  }
];

const array2 = [{
    "orgId": 101,
    "orgGN": "ABC",
    "dId": 494,
    "name": "Test1",
  },
  {
    "orgId": 105,
    "orgGN": "PDC",
    "dId": 420,
    "name": "Test5",
  },
  {
    "orgId": 106,
    "orgGN": "ASR",
    "dId": 44,
    "name": "Test6",
  }
];

function intersection(array1, array2, field, value) {
  const array2OrgIds = array2.map(item => item.orgId);

  return  array1.filter((el) => !array2OrgNames.includes(el.orgId) && el[field] === value);
}

console.log(intersection(array1, array2, "orgGN", "ABC"));

完整代码如下:

 tap.cancelsTouchesInView = false

在外部点击时使用分散软键盘的最佳解决方案是什么?

我将解释一种情况:

考虑一下:您的UISearchBar位于顶部, 然后添加标题的tableview!

解决方案很简单:

  1. 打开或关闭跟踪软键盘
  2. 将手势识别添加到标题视图
  3. 表视图didSelectRowAt的实现委托

完整代码:

 let tap = UITapGestureRecognizer(target: self, action: #selector(self.superViewClicked))
        tap.numberOfTapsRequired = 1
        tap.delegate = self
        tap.cancelsTouchesInView = false
        self.view.addGestureRecognizer(tap)




  @objc func superViewClicked(){
        
        self.searchTF.resignFirstResponder()
    }

它如何工作:

  1. 如果软键盘已打开并且用户单击标题软键盘已关闭
  2. 如果打开了软键盘并且用户单击了单元格,则键盘关闭并且没有执行单元格单击

答案 33 :(得分:0)

对于集合视图:

// the keyboard follows the dragging touch off screen, and may be pulled upward again to cancel the dismiss
collectionView.keyboardDismissMode = .interactive
// dismisses the keyboard when a drag begins
collectionView.keyboardDismissMode = .onDrag

答案 34 :(得分:0)

在viewDidLoad中 迅捷4.2 像这样的代码

let viewTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action:#selector(dismissKeyboard))
        view.addGestureRecognizer(viewTap)
@objc func dismissKeyboard() {
        view.endEditing(true)
    }

答案 35 :(得分:0)

所以我只需要解决这个问题,以前的答案都没有为我提供开箱即用的功能。我的情况:UISearchBar,以及屏幕上的其他一些控件。我想在搜索栏外面点击以关闭键盘,但传播到任何其他控件。当键盘被隐藏时,我希望所有控件都能正常工作。

我做了什么:

1)在我的视图控制器中实现自定义触摸处理程序。

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
    if searchBar.isFirstResponder()
    {
        // This causes the first responder, whoever it is, to resign first responder, and hide the keyboard.
        // We also "eat" the touch here and not allow it to propagate further.
        view.endEditing(true)
    }
    else
    {
        // OK to propagate the touch
        super.touchesBegan(touches, withEvent: event)
    }
}

2)添加了几个委托方法(我的是UISearchBar,但UITextField也有类似的方法)。下面代码中的controlContainerView是一个UIView,里面有一堆按钮。请注意,在超级视图上设置userInteractionEnabled会禁用其所有子视图。

 func searchBarTextDidBeginEditing(searchBar: UISearchBar)
 {
     controlContainerView.userInteractionEnabled = false
     someButton.userInteractionEnabled = false
 }

 func searchBarTextDidEndEditing(searchBar: UISearchBar)
 {
     searchBar.resignFirstResponder()

    // Done editing: enable the other controls again.

    controlContainerView.userInteractionEnabled = false
    someButton.userInteractionEnabled = false
}

答案 36 :(得分:0)

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    super.view.endEditing(true)
    super.touchesBegan(touches, withEvent: event)
}

答案 37 :(得分:0)

只需在.m文件中使用此代码,当用户点击文本字段外,它将重新签名文本字段。

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
  [textfield resignFirstResponder];
 }