当用户在文本框外的其他区域点击时,如何关闭键盘?

52

今天我尝试在我的iPod(iOS 6.1.3)上运行我的代码,发现了一些有趣的东西...

首先,当我点击文本框时,键盘会弹出,但是当我在文本框外部的其他地方点击时,它不会隐藏。

因此,我决定搜索并找到了这个解决方案:

_fieldEmail.delegate = self;
_fieldEmail.returnKeyType = UIReturnKeyDone;

_fieldPassword.delegate = self;
_fieldPassword.returnKeyType = UIReturnKeyDone;

_fieldRegisterName.delegate = self;
_fieldRegisterName.returnKeyType = UIReturnKeyDone;

_fieldRegisterEmail.delegate = self;
_fieldRegisterEmail.returnKeyType = UIReturnKeyDone;

_fieldRegisterPassword.delegate = self;
_fieldRegisterPassword.returnKeyType = UIReturnKeyDone;

它可以运行... 它在键盘底部提供了一个“完成”按钮,现在可以通过按下该按钮来隐藏键盘。

但是我这里有两个问题:

  1. 只有在点击“完成”按钮时键盘才会隐藏,而不是在文本字段之外的其他区域点击。我不知道这在iOS世界中是否正常,但通常我看到很多应用程序不会这样做。
  2. 有没有办法循环执行此过程,以便我不必手动添加所有文本字段的委托?如何做到这一点?

这就是我需要知道的全部内容。


这里有一些很好的答案。 - ICL1901
可能是重复的问题:iphone,当触摸文本字段外部时关闭键盘 - icodebuster
15个回答

82

以下代码将适用于UIView中的所有组件,适用于所有UITextField

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    for (UIView * txt in self.view.subviews){
        if ([txt isKindOfClass:[UITextField class]] && [txt isFirstResponder]) {
            [txt resignFirstResponder];
        }
    }
}

或者

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

1
当使用 UIPresentationFormSheet 模态展示视图控制器时,这似乎不起作用。 - fatuhoku
5
如果您的视图上有控件并点击它们,这将无法起作用。 - Duck
1
注意,这已经在Swift 2中被更改为覆盖func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)。 - jesses.co.tt
这个方法不应该也调用父类的方法吗? - rtcarlson

30
  1. 在您的视图中添加一个UITapGestureRecogniser,并调用resignFirstResponder

在viewDidLoad中:

UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] 
                                   initWithTarget:self
                                   action:@selector(hideKeyBoard)];

[self.view addGestureRecognizer:tapGesture];

然后:

-(void)hideKeyBoard {
       [yourTextField resignFirstResponder];
}

2.您可以创建 UITextField 的子类,但是除非您有1000个文本字段,否则按照当前的方式做也可以。


我按照你说的做了:-(void)dismissKeyboard { [UITextField fieldEmail : hideKeyBoard]; } 这是Xcode的提示:使用了未声明的标识符'hideKeyBoard',那么在哪里声明hideKeyBoard呢? - Saint Robson
抱歉,我的回答有误;我使用了“resignFirstResponder”进行了编辑。 - LudoZik
2
如果您的屏幕上还有其他需要点击的控件,例如表格单元格上的转场,那么这种方法将无法正常工作。是否有一种方法只在键盘显示时调用轻击手势? - mreynol
谢谢,我使用了选择器,但是结合 [self.view endEditing:YES]; 在 -(void)hideKeyBoard { 方法中。它有效地解决了问题。 - Nicola

19

这是关于 Xcode 6.0.1Swift 编程问题。

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleSingleTap:")
    tapRecognizer.numberOfTapsRequired = 1
    self.view.addGestureRecognizer(tapRecognizer)
}

func handleSingleTap(recognizer: UITapGestureRecognizer) {
    self.view.endEditing(true)
}

这很棒,但在最新版本中,选择器会抛出一个错误。请使用以下代码替换:let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleSingleTap(_:))) - Wade
现在已经足够了:let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleSingleTap)) - Colibri

7

关闭键盘

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

7

使用方式

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

和方法的代码

-(void)handleSingleTap:(UITapGestureRecognizer *)sender{
    [self.TextFiledName resignFirstResponder];

}

OR _ 最佳的其他选择是

只需添加

  [self.view endEditing:YES];

当您从视图中的任何位置轻触时,键盘将隐藏:)

4

简单易用,

使用IQKeyboardManager并将下面这行代码放在AppDelegate.m中。

[[IQKeyboardManager sharedManager] setShouldResignOnTouchOutside:YES];

3

我通常所做的是调用

[field resignFirstResponder]; 

从视图上方的不可见按钮触发。我相信有更好的方法来实现它。这是我在应用程序中做这个功能已经有一段时间了。


把这段代码放在哪里?我尝试了这样写:_fieldEmail.delegate = self; _fieldEmail.returnKeyType = UIReturnKeyDone; [_fieldEmail resignFirstResponder]; 但它仍然不会改变行为。 - Saint Robson

1

|*| 关闭UITextField的键盘:为ViewController覆盖touchesBegan:withEvent:方法

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

|OR|

override func viewDidLoad()
{
    super.viewDidLoad()
// For tapping outside text box
    self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DismisKeyPadFnc)))
}

// For tapping outside text box
func DismisKeyPadFnc()
{
    view.endEditing(true)
}

|*| 在个别文本框中关闭UITextField键盘:

class NamVcc: UIViewController, UITextFieldDelegate
{
    @IBOutlet var NamTxtBoxVid: UITextField!

    override func viewDidLoad()
    {
        super.viewDidLoad()

    // For hitting return key
        NamTxtBoxVid.delegate = self

    // For tapping outside text box
        self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DismisKeyPadFnc)))
    }

/* For hitting return key */
    func textFieldShouldReturn(NamTxtBoxPsgVid: UITextField) -> Bool
    {
        NamTxtBoxPsgVid.resignFirstResponder()
        return true
    }

/* For tapping outside text box */
    func DismisKeyPadFnc()
    {
        view.endEditing(true)
    }
}


|*| 实现下一步按钮点击:
1)您需要在xib / Storyboard或代码中按文本字段的增量顺序设置标记。
2)为每个文本字段设置委托。
3)然后将以下代码粘贴到您的视图控制器中以获得所需效果:

func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
{
    let NxtTxtBoxTagVal : Int = TxtBoxPsgVar.tag + 1

    let NxtTxtBoxVal: UIResponder? = TxtBoxPsgVar.superview?.superview?.viewWithTag(NxtTxtBoxTagVal)

    if let TxtBoxVal = NxtTxtBoxVal
    {
        // Found next responder, so set it.
        TxtBoxVal.becomeFirstResponder()
    }
    else
    {
        // Not found, so remove keyboard.
        TxtBoxPsgVar.resignFirstResponder()
    }
    return true
}

1
我遇到了完全相同的问题。通常你想要的是,无论你在应用程序中的哪个位置点击(显示在主/当前UIView中),但不是在键盘上,都可以关闭它。在搜索了一些聪明的解决方案并测试了几个之后,我认为最好的方法是扩展/子类化/实现UIGestureRecognizerDelegate。
由于许多控件(如UITableView等)可以响应手势(选择、滚动等),如果你只是向整个(主)ViewController的视图添加UITapGestureRecognizer来关闭键盘,用户体验就不是最好的,因为用户需要点击两次,如果他不打算关闭键盘,而是想在应用程序的当前“主”视图中选择一行UITableView。
由于我对整个iOS和Swift的事情还很新,并且Swift代码示例很少,这里是我的完整键盘控制片段:
class ViewController: UIViewController, UIGestureRecognizerDelegate {

override func viewDidLoad(){
     self.initializeCloseKeyboardTap()
}

func initializeCloseKeyboardTap() {

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboardOpen:", name: UIKeyboardDidShowNotification, object: nil)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboardClose:", name: UIKeyboardDidHideNotification, object: nil)
    let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleOnTapAnywhereButKeyboard:")
    tapRecognizer.delegate = self //delegate event notifications to this class
    self.view.addGestureRecognizer(tapRecognizer)

}


func onKeyboardClose(notification: NSNotification) {
    println("keyboardClosed")
}

func onKeyboardOpen(notification: NSNotification) {
    println("keyboardOpen")
}

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    self.view.endEditing(true)
    return false
}

你可以将其嵌套在ViewController中,并在viewDidLoad实现中调用initiallizeCloseKeyboardTa()... 它还通过NSNotificationCenter UIKeyboardDidShowNotification和UIKeyboardDidHideNotification实现了通知观察器,以便尽快接收键盘打开或关闭的事件。希望这能为其他人节省一些时间 :-)

我将这个应用到了我的textField上,效果很好。如果你在textField外面的任何地方点击,它会关闭键盘。但有一个问题...如果你点击textField本身,它也会关闭键盘。我该如何防止这种情况发生? - peacetype

1
这是我的做法:

在 myView 的 .h 文件中:

@property (strong) UITextField * savedTextField;

在myView的.m文件中:
@implementation myView

@synthesize savedTextField;

在myView的初始化程序中:
[self setSavedTextField: nil];

在myView的textField代理区域,我保存了当前激活的textField的ID:
- (BOOL) textFieldShouldBeginEditing: (UITextField *) textField
   {
   [self setSavedTextField: textField];
   .
   .
   .
   return( YES );
   }

在myView的例行程序中,当访问其他控件时,我编写了一些代码来查看是否有textField处于活动状态,如果有,则调用它放弃FirstResponder状态,然后将nil放入savedTextField属性中。请注意保留HTML标签。
- (void) handleCtrlEvents: (UIControl *) aCtrl
  {
  if ( [self savedTextField] != nil )
     {
     [[self savedTextField] resignFirstResponder];
     [self setSavedTextField: nil];
     }
  .
  .
  .
  }

这对我来说很干净地运行。

我尝试了 icodebuster 的建议,它比我的建议更好,因为当用户在视图中的任何位置点击时,它会导致适当的 resignFirstResponder 发生,并且你不需要跟踪任何东西。很棒。 - Gallymon
完美的答案。谢谢。 - Sathya Baman

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