iOS--彻底解决UITextField键盘先显示后自动消失的问题

场景重现:在UITextField的键盘处于显示状态的时候,点击一个按钮,首先取消UITextField的第一响应者,弹出UIAlertView,然后点击UIAlertView上的"取消"或者"确定"后,键盘会有弹出然后消失的动画.

代码如下:

//按钮的点击事件
-(void)buttonClick:(UIButton *)button{
   [self.textField resignFirstResponder];
   UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"这是一个alert" message:@"测试用的" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
   [alert show];
}
//alertView的代理方法
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
   if (buttonIndex == 0) {
    
   } else{
    
   }
}

一 这里先把最终解决的办法写在这:

1 第一种解决办法,在弹出取消UITextField的第一响应者代码之后做一个延迟处理,代码如下:

//按钮的点击事件
-(void)buttonClick:(UIButton *)button{
  [self.textField resignFirstResponder];
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), 
   dispatch_get_main_queue(), ^{
   UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"这是一个alert" message:@"测试用的" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
   [alert show];
  });
}

2 用最新的(UIAlertController)弹窗方式

-(void)buttonClick:(UIButton *)button{
  [self.textField resignFirstResponder];
if([[[UIDevice currentDevice] systemVersion] compare:@"8.0"] == NSOrderedDescending){
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"这是一个alert" message:@"测试用的" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    [alert show];
} else{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"这是一个alert" message:@"测试用的" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *actionOK = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
       
    }];
    UIAlertAction *actionCancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    [alertController addAction:actionOK];
    [alertController addAction:actionCancel];
    
    [self presentViewController:alertController animated:YES completion:nil];
}

}

二 探索

1 既然点击UIAlertView的"取消"或者"确定"后键盘弹出了,我想是不是取消UITextField第一响应者失败了,然后我在alertView的代理方法里边加上了取消第一响应者方法,代码如下:

//alertView的代理方法
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    [self.textField resignFirstResponder];
   if (buttonIndex == 0) {
    
   } else{
    
   }
}

满怀希望的运行了一下,失败了!

2 换一个地方试试

//alertView的代理方法
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    
   if (buttonIndex == 0) {
    [self.textField resignFirstResponder];
   } else{
    [self.textField resignFirstResponder];
   }
}

运行,失败!

3 经过1,2步的试验,看来在alertView的代理方法里加代码是解决不了问题的,我往上一步看,是在弹出alertView的方法(即按钮的点击方法)的问题,然后我先注释了弹出alertView的代码:

//按钮的点击事件
-(void)buttonClick:(UIButton *)button{
   [self.textField resignFirstResponder];
   //UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"这是一个alert" message:@"测试用的" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
   //[alert show];
}

运行,发现键盘正常退回!

猜想:[alert show]的时候会有一个蒙层,苹果为了保证美观性,暂时强制隐藏键盘,从而导致resignFirstResponder 的键盘消失动画延迟,当点击alertView上边的"取消"和"确定"之后处理了键盘消失动画.

换一种说法就是:当runLoop接收到UITextField结束第一响应者的消息后,放在了调用队列中,不会马上执行键盘收起,这个时候又接收到了[alert show]的消息,系统会优先处理[alert show]的消息,挂起[UITextField resignFirstResponder];当处理完alertView的时候,再继续执行resignFirstResponder的键盘动画;

4 由第3步的猜想,有了一个解决办法,延迟弹出alertView,具体代码如下:

//按钮的点击事件
-(void)buttonClick:(UIButton *)button{
   [self.textField resignFirstResponder];
   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
   UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"这是一个alert" message:@"测试用的" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
   [alert show];
}
});

5 大家应该知道的是,UIAlertView在iOS9.0就被废弃了,改用UIAlertController;那么苹果是否考虑到这个问题了呢?下边是我的测试代码:

//按钮的点击事件
-(void)buttonClick:(UIButton *)button{
if([[[UIDevice currentDevice] systemVersion] compare:@"9.0"] == NSOrderedDescending){
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"这是一个alert" message:@"测试用的" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    [alert show];
} else{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"这是一个alert" message:@"测试用的" preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *actionOK = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    UIAlertAction *actionCancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    [alertController addAction:actionOK];
    [alertController addAction:actionCancel];
    
    [self presentViewController:alertController animated:YES completion:nil];
}

运行,也是可以的!

好了,到此本次探索结束!

三 总结猜想:

此问题的原因猜想是:
[alert show]的时候会有一个蒙层,苹果为了保证美观性,暂时强制隐藏键盘,从而导致resignFirstResponder 的键盘消失动画延迟,当点击alertView上边的"取消"和"确定"之后处理了键盘消失动画.

换一种说法就是:当runLoop接收到UITextField结束第一响应者的消息后,放在了调用队列中,不会马上执行键盘收起,这个时候又接收到了[alert show]的消息,系统会优先处理[alert show]的消息,挂起[UITextField resignFirstResponder];当处理完alertView的时候,再继续执行resignFirstResponder的键盘动画;

解决此问题的方法有两个:文章开头已经写明,本人推荐第二种用新的API的Fi方法

四 番外篇

UIAlertController的常用的API:

//快速初始化方法
+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(UIAlertControllerStyle)preferredStyle;
//添加按钮
- (void)addAction:(UIAlertAction *)action;
其他
@property (nonatomic, readonly) NSArray<UIAlertAction *> *actions;
@property (nonatomic, strong, nullable) UIAlertAction *preferredAction NS_AVAILABLE_IOS(9_0);
- (void)addTextFieldWithConfigurationHandler:(void (^ __nullable)(UITextField *textField))configurationHandler;
@property (nullable, nonatomic, readonly)   NSArray<UITextField *> *textFields;
@property (nullable, nonatomic, copy) NSString *title;
@property (nullable, nonatomic, copy) NSString *message;
@property (nonatomic, readonly) UIAlertControllerStyle preferredStyle;

UIAlertAction常用的API:
//快速初始化方法
+ (instancetype)actionWithTitle:(nullable NSString *)title style:(UIAlertActionStyle)style handler:(void (^ __nullable)(UIAlertAction *action))handler;
其他
@property (nullable, nonatomic, readonly) NSString *title;
@property (nonatomic, readonly) UIAlertActionStyle style;
@property (nonatomic, getter=isEnabled) BOOL enabled;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容