关闭iOS虚拟键盘的六种方法(转)

来源:互联网 发布:卫龙淘宝辣条直播视频 编辑:程序博客网 时间:2024/06/05 20:19

在iOS应用中,输入操作的方式之一是使用虚拟键盘。打开很容易,关闭却有一些讲究。这需要我们去研究一下。我所知道的需要打开虚拟键盘的三类视图对象分别是UITextField,UITextView和UISearchBar。实现这个操作的方法大体是点击虚拟键盘的return键或done键等关闭它,或者是点击键盘之外的区域关闭它。最好的方法是点击虚拟键盘之外的区域来关闭它的方法,采用的是覆盖视图控制器的hitTest:withEvent:方法实现。

我就UITextField如何关闭虚拟键盘举个例子,介绍我所知道的几种方法。


第一种方法,使用它的委托UITextFieldDelegate中的方法textFieldShouldReturn:来关闭虚拟键盘。


在UITextField视图对象如birdNameInput所在的类中实现这个方法。

 
[plain] view plaincopyprint?
  1. (BOOL)textFieldShouldReturn:(UITextField *)textField  
  2.     if ((textField == self.birdNameInput) || (textField == self.locationInput))  
  3.         [textField resignFirstResponder];  
  4.      
  5.     return YES;  
  6.  


这样,在输入框birdNameInput中打开虚拟键盘后,轻击键盘的return键就会自动关闭掉虚拟键盘。

第二种方法,将birdNameInput的属性中Return Key修改为done,再定义一个方法和Done键的Did End OnExit连接。通过轻击done键触发这个事件来关闭虚拟键盘。

定义的方法如下:

 
[plain] view plaincopyprint?
  1. (IBAction) textFieldDoneEditing:(id)sender  
  2.  
  3.         [sender resignFirstResponder];  
  4.  


这两个方法都是轻击虚拟键盘上一个键来关闭它。这属于精确操作,而手指不像鼠标,做这种操作不容易。因此就UI层面而言,这两个方法都不是最好的方法。
在iphone或ipad屏幕上,虚拟键盘占用的面积大小是有限的。通过轻击虚拟键盘之外的区域而关闭虚拟键盘。

 

第三种方法,通过轻击键盘之外的空白区域关闭虚拟键盘。


在birdNameInput所属的视图控制器类的viewDidLoad方法中定义一个UITapGestureRecognizer的对象,然后将它赋值为它的视图。


[plain] view plaincopyprint?
  1. UITapGestureRecognizer *tap   
  2. [[UITapGestureRecognizer alloc]   initWithTarget:self action:@selector(dismissKeyboard)];  
  3. [self.view addGestureRecognizer:tap];  
  4. [tap release];  


再定义一下选择器调用的方法dismissKeyboard。

[plain] view plaincopyprint?
  1. -(void)dismissKeyboard  
  2.        [birdNameInput resignFirstResponder];  
  3.  
 
如果屏幕上有多个textField的话,一个一个地列出来就有些麻烦。那么将方法修改一下,如下:

[plain] view plaincopyprint?
  1. -(void)dismissKeyboard  
  2.     NSArray *subviews [self.view subviews];  
  3.     for (id objInput in subviews)  
  4.         if ([objInput isKindOfClass:[UITextField class]])  
  5.             UITextField *theTextField objInput;  
  6.             if ([objInput isFirstResponder])  
  7.                 [theTextField resignFirstResponder];  
  8.              
  9.          
  10.      
  11.  


如果这个屏幕上的视图对象很复杂的话,另当别论。
这个方法是编码新建一个手势对象。也可以直接使用interfacebuilder图形化开发工具,在storyboard中拉入一个手势对象到视图控制器类中,再将此手势对象建立一个IBACTION,名称可以是dismissKeyboard。

第四种方法,通过轻击键盘之外的空白区域关闭虚拟键盘。


将屏幕上的view也就是textField的父视图拖一个touchdown事件出来,和一个能关闭虚拟键盘的方法连接。如果视图没有touchdown事件,可将view的父类从UIView修改为UIButton。

首先定义并实现一个方法backgroundTap:。

 

[plain] view plaincopyprint?
  1. (IBAction) backgroundTap:(id)sender  
  2.  
  3.         NSArray *subviews [self.view subviews];  
  4.     for (id objInput in subviews)  
  5.         if ([objInput isKindOfClass:[UITextField class]])  
  6.             UITextField *theTextField objInput;  
  7.             if ([objInput isFirstResponder])  
  8.                 [theTextField resignFirstResponder];  
  9.              
  10.          
  11.      
  12.  
 

 

然后选择背景视图的TouchDown事件,连接backgroundTap:即可。这样只要轻击一下虚拟键盘之外的区域,就能关闭虚拟键盘。这些方法都是使用resignFirstResponder方法来关闭虚拟键盘,还有其他的方法。

 

第五种方法,使用endEditing:方法


在所在的视图控制器类中,覆盖这个方法。 

[plain] view plaincopyprint?
  1. (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  
  2.       [[self view] endEditing:YES];  
  3.  

This method looks at the current view and its subview hierarchy forthe text field that is currently the first responder. If it findsone, it asks that text field to resign as first responder. If theforce parameter is set to YES, the text field is never even asked;it is forced to resign.

但是,如果这个屏幕很复杂,虚拟键盘之外的区域中有很多按钮。轻击这些区域时可能会轻击到这些按钮,这样虚拟键盘就不能关闭。

要是找到一个没有按钮的空白区域都不容易且还有隐藏的视图对象时,通过轻击虚拟键盘之外的区域关闭虚拟键盘的方法实现起来就难了。

 

第六种方法,覆盖hitTest:withEvent:方法

在stackoverflow.com上,有人这样总结。说使用hitTest:withEvent:方法是最好的,也是最容易的解决方法。
I think the easiest (and best) way to do this is to subclass yourglobal view and use hitTest:withEvent method to listen to anytouch.
Touches on keyboard aren't registered, so hitTest:withEvent is onlycalled when you touch/scroll/swipe/pinch... somewhere else, thencall [self endEditing:YES].
This is better than using touchesBegan because touchesBegan are notcalled if you click on a button on top of theview.
It is better than UITapGestureRecognizer which can't recognize ascrolling gesture for example. It is also better than using a dimscreen because in a complexe and dynamic user interface, you can'tput dim screen every where. Moreover, it doesn't block otheractions, you don't need to tap twice to select a button outside(like in the case of a UIPopover).
Also, it's better than calling [textField resignFirstResponder],because you may have many text fields on screen, so this works forall of them.

因此,我再建立一个继承UIView的视图类。在这个视图类中,覆盖hitTest:withEvent:方法,增加[selfendEditing:YES]方法。
[plain] view plaincopyprint?
  1. (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event  
  2. UIView *result [super hitTest:point withEvent:event];  
  3. [self endEditing:YES]  
  4. return result;  
  5.  


我将视图控制器的主视图所属类修改为这个新建视图类。这样在屏幕上轻击任何位置都会关闭虚拟键盘。
这个方法是最简单,也是最好的关闭虚拟键盘的方法。

使用好hitTest:withEvent:这个方法,还可以实现很多很复杂的功能。

Theimplementation of hitTest:withEvent: in UIResponder does thefollowing:

       It calls pointInside:withEvent: of self
       If the return is NO, hitTest:withEvent: returns nil. the end of thestory.
       If the return is YES, it sends hitTest:withEvent: messages to itssubviews. it starts from the top-level subview, and continues toother views until a subview returns a non-nil object, or allsubviews receive the message.
       If a subview returns a non-nil object in the first time, the firsthitTest:withEvent: returns that object. the end of thestory.
       If no subview returns a non-nil object, the firsthitTest:withEvent: returns self

This process repeats recursively, so normally the leaf view of theview hierarchy is returned eventually.
However, you might override hitTest:withEvent to do somethingdifferently. In many cases, overriding pointInside:withEvent: issimpler and still provides enough options to tweak event handlingin your application.
0 0