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 *actions;
@property (nonatomic, strong, nullable) UIAlertAction *preferredAction NS_AVAILABLE_IOS(9_0);
- (void)addTextFieldWithConfigurationHandler:(void (^ __nullable)(UITextField *textField))configurationHandler;
@property (nullable, nonatomic, readonly)   NSArray *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;

你可能感兴趣的:(iOS--彻底解决UITextField键盘先显示后自动消失的问题)