最近写登录界面,界面是网红脸——几个输入框,几个按钮和一个开关。
点击按钮,有时界面是不会跳转的,这时如果有键盘,让键盘 dismiss 是正常的需求,于是小小地研究了一下~~~
两种情况:
1,点击空白区域,可以通过在触摸方法中实现(这个大家都可以搜到,so,这不是我想说的)——
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (![[touches anyObject].view isKindOfClass:[UITextField class]]) {
[self.view endEditing:YES];
}
}
2,点击UIButton,UISwitch等本身可以处理响应的控件,因为Responder Chain的原因,控件的触发的事件会覆盖UIView本身的响应,所以要在这时收起键盘只能在触发事件中处理,可以在事件中加入如下代码:
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
即:
- (IBAction)buttonDidPress:(id)sender
{
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
}
这个其实也很容易搜到,所以也不是我想说的...
我想说的是如果按钮比较多,这样一个个写起来岂不是太麻烦了,虽然每个方法里只加一行代码,但看起来还是很蛋疼....
所以我想要一个所有按钮点击的时候都会走的方法,于是乎,我写了一个category,并且在category中复写了- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event方法,并且在该方法中resignFirstResponder,即:
- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
NSLog(@"%s", __func__);
[super sendAction:action to:target forEvent:event];
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
}
注意,在该方法中一定要调用父类的这个方法,否则你的按钮就罢工了...
那我要是点击开关的时候也想要收起键盘呢?简单,因为这个方法是UIControl里面的,而且UIButton和UISwitch都是UIControl的子类,所以再照葫芦画瓢写一个UISwitch的category就ok了。
这样点击按钮和开关就都可以关掉键盘了,我蛋疼地看着两个蛋疼的category,想着如何解决这隐隐的忧伤————两个category里面的方法都是一样的,不可以写一个吗?
于是我又蛋疼地上路了,写了个UIControl的category,又复写了那个方法,满以为会不疼了,结果并不满意,Xcode出示了黄牌:Category is implementing a method which will also be implemented by its primary class。原因是这个方法是UIControl已有的,就不建议再在category中复写,这样写会导致UIControl的方法列表中有两个一样的方法签名,运行的时候会产生unexpected后果。
A
好吧,既然影子不让有,那我只能碰你真身了,因为我们有牛( )闪闪放光芒的runtime,我就
C
可以写个别的名的方法实现这个功能,并且都不再给你走自己方法的机会:
+ (void)load
{
Method originalMethod = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method expectMethod = class_getInstanceMethod(self, @selector(resignFirstResponderWithOriginalAction:to:forEvent:));
method_exchangeImplementations(originalMethod, expectMethod);
}
- (void)resignFirstResponderWithOriginalAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
NSLog(@"%s", __func__);
[self resignFirstResponderWithOriginalAction:action to:target forEvent:event];
[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
}
OK,大功告成,没有黄牌,键盘下来!
以上代码均已放到git上,大家有兴趣的可以看看。
不过鉴于以上需求均为鄙人遐想所求,现实中遇到较少,且以上实现方式是Universal的,为避免误伤,还是慎用的好,我这么想这么做也是为了开阔开阔思路~~
首次写文,难免有瑕疵疏漏,还望大牛提出宝贵意见,不胜感激!