iOS8.0+ 第三方输入法多次发送UIKeyboard相关的通知

来源:互联网 发布:如何安装vb 编辑:程序博客网 时间:2024/06/05 14:55

在iOS8.0+的系统中提供了对第三方输入法的支持,这对广大的果粉来说或许是一个好消息,但对于万千的iOS应用程序开发人员来说更关心的是产品经理是否又要根据这更改需求或是第三方输入法是否会引发什么不必要的bug,毕竟以前写的程序只针对系统输入法。不巧的是这样的事情就发生在最近开发的App中——使用第三方输入法会三次接收到UIKeyboardWillChangeFrameNotification的通知(在一次点击UITextField的时候)。

具体的需求是这样的:当点击处于视图控制器底部的UITextField时想要它跟随弹出的键盘一起上升到与键盘相邻的位置,并在输入框视图的上部添加一个遮罩,点击遮罩时让输入框失去焦点。


要实现这种效果有很多种方法:在iOS5.0以前由于虚拟键盘的高度固定可以通过实现UITextField的代理方法- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField来实现:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{    UIView *alphaCoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - 216 - 40)];    [alphaCoverView setBackgroundColor:[UIColor blackColor]];    alphaCoverView.alpha = 0;    [UIView animateWithDuration:0.25 animations:^{        alphaCoverView.alpha = 0.4;    }];    alphaCoverView.tag = 10001;    UITapGestureRecognizer *tapToResignirstResponder = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(textFielfWillResignirstResponder)];    [alphaCoverView addGestureRecognizer:tapToResignirstResponder];    [[[UIApplication sharedApplication].delegate window] addSubview:alphaCoverView];    [UIView animateWithDuration:0.3 animations:^{        self.m_spaceToBottom.constant += 216 - 40;        [self.view layoutIfNeeded];    }];    return YES;}
因为这里用的是AutoLayout,所以修改UITextField的父视图距离底部的约束的值m_spaceToBottom.constant是最好的选择(直接修改frame这这里不可行),未使用布局约束的可以直接修改frame。遮罩视图alphaCoverView轻怕的触发方法实现如下:
- (void)textFielfWillResignirstResponder{    UIView *view = [[[UIApplication sharedApplication].delegate window] viewWithTag:10001];    [view removeFromSuperview];    [self.m_periodTF resignFirstResponder];    [self.m_multipleTF resignFirstResponder];    [UIView animateWithDuration:0.3 animations:^{        self.m_spaceToBottom.constant -= 216 - 40;        [self.view layoutIfNeeded];    }];}
在iOS5.0以后因为键盘的高度不等和其他的原因,大家通常通过监听键盘将要出现的通知[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];来实现上述效果(只需将TextField的代理方法的实现粘贴到keyboardWillShow中即可)。这样做也有一个弊端,当用户在已经弹出的键盘中切换输入法时,键盘高度变化,keyboardWillShow会再次触发,那么该方法内的实现就要修改:

</pre><pre name="code" class="objc">- (void)keyboardWillShow:(NSNotification *)notice{    NSValue *value = [[notice userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"];    float keyEnd_y = [value CGRectValue].origin.y;    float animationDuration = [[notice userInfo][@"UIKeyboardAnimationDurationUserInfoKey"] floatValue];    UIView *alphaCoverView = [[[UIApplication sharedApplication].delegate window] viewWithTag:10001];    if (!alphaCoverView) {        alphaCoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, keyEnd_y - 45)];        [alphaCoverView setBackgroundColor:[UIColor blackColor]];        alphaCoverView.alpha = 0.0;        alphaCoverView.tag = 10001;        UITapGestureRecognizer *tapToResignirstResponder = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(textFielfWillResignirstResponder)];        [alphaCoverView addGestureRecognizer:tapToResignirstResponder];        [[[UIApplication sharedApplication].delegate window] addSubview:alphaCoverView];    }    [UIView animateWithDuration:animationDuration animations:^{        alphaCoverView.frame = CGRectMake(0, 0, SCREEN_WIDTH, keyEnd_y - 45);//45是绿色视图的高        alphaCoverView.alpha = 0.4;    }];    float constant = 0.0;//46是上图中底部灰色视图的高,也就是绿色视图距离底部的高度    constant = SCREEN_HEIGHT - keyEnd_y - 46;    [UIView animateWithDuration:animationDuration animations:^{        self.m_spaceToBottom.constant = constant;        [self.view layoutIfNeeded];    }];}
事情发展到到iOS8.0+又有了变化,(1)对于第三方输入法一次点击UITextField的事件中会触发三次UIKeyboardWillShowNotification的通知(已知的有百度和搜狗),(2)百 度的第三方输入法的键盘的高度可以随意调整。所以针对所有的可能的情况监听键盘的UIKeyboardWillChangeFrameNotification的通知是最好的选择(私有观点)。做法的如下:

(1)在视图控制器中添加BOOL值:BOOL shouldResignFirstResponder;用于记录键盘frame改变时是否是结束输入、收回键盘的操作。

(2)将视图控制器添加为UIKeyboardWillChangeFrameNotification通知的观察者:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardFrameChange:) name:UIKeyboardWillChangeFrameNotification object:nil];

(3)实现keyboardFrameChange方法:

- (void)keyboardWillShow:(NSNotification *)notice{    NSValue *value = [[notice userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"];    float keyEnd_y = [value CGRectValue].origin.y;    float animationDuration = [[notice userInfo][@"UIKeyboardAnimationDurationUserInfoKey"] floatValue];    if(!shouldResignFirstResponder){        UIView *alphaCoverView = [[[UIApplication sharedApplication].delegate window] viewWithTag:10001];        if (!alphaCoverView) {            alphaCoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, keyEnd_y - 45)];            [alphaCoverView setBackgroundColor:[UIColor blackColor]];            alphaCoverView.alpha = 0.0;            alphaCoverView.tag = 10001;            UITapGestureRecognizer *tapToResignirstResponder = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(textFielfWillResignFirstResponder)];            [alphaCoverView addGestureRecognizer:tapToResignirstResponder];            [[[UIApplication sharedApplication].delegate window] addSubview:alphaCoverView];        }        [UIView animateWithDuration:animationDuration animations:^{            alphaCoverView.alpha = 0.4;            alphaCoverView.frame = CGRectMake(0, 0, SCREEN_WIDTH, keyEnd_y - 45);//45是绿色视图的高        }];    }    float constant = 0.0;    if (shouldResignFirstResponder) {        //收回键盘时,将约束的值复原        constant = SCREEN_HEIGHT - keyEnd_y;        [UIView animateWithDuration:animationDuration animations:^{            m_spaceToBottom.constant = constant;            [self.view layoutIfNeeded];        }];        shouldResignFirstResponder = NO;    }else{        constant = SCREEN_HEIGHT - keyEnd_y - 46;//46是上图中底部灰色视图的高,也就是绿色视图距离底部的高度        [UIView animateWithDuration:animationDuration animations:^{            m_spaceToBottom.constant = constant;            [self.view layoutIfNeeded];        }];    }}
(4)实现遮罩轻拍的轻拍方法:

- (void)textFielfWillResignFirstResponder{    UIView *view = [[[UIApplication sharedApplication].delegate window] viewWithTag:10001];    [view removeFromSuperview];    shouldResignFirstResponder = YES;    [m_issueTF resignFirstResponder];    [m_mulTF resignFirstResponder];}
注: m_spaceToBottom是绿色视图的距离底部的布局约束,SCREEN_WIDTH屏幕宽、SCREEN_HEIGHT屏幕高,m_issueTF和m_mulTF图中的俩个输入框。

0 0
原创粉丝点击