美文网首页iOS学习iOS Developer程序员
iOS 实现输入框跟随键盘自动上移

iOS 实现输入框跟随键盘自动上移

作者: 还是不够辣 | 来源:发表于2017-04-12 18:15 被阅读1173次

    场景还原

    有些时候在包含输入框的页面中,点击输入框输入会因键盘弹起而遮挡住一部分输入框,影响用户体验。iOS在默认情况下并不会处理这种问题,不过我们可以自己实现键盘弹起输入框自动上移的效果。

    测试页面

    实现思路

    观察键盘的弹起与收回,当弹起的键盘会遮挡住输入框时,将输入框跟随键盘一并上移合适的距离,当键盘收回时,输入框回到原始状态。

    具体方案

    1. 注册两个观察者,观察键盘的弹起与收回

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    

    2. 在上面的keyboardWillShow和keyboardWillHide方法中分别实现输入框的上移和还原

    • 上移
      当弹起的键盘遮住了页面上的输入框时,我们应该将输入框移至键盘之上,而键盘没有遮到输入框时,并不需要操作。因此在ios的坐标系下,我们可以分别获取键盘弹起后上端的Y坐标和输入框下端的Y坐标,通过做差可以判断出键盘是否遮住了输入框。上移我们可以采用view的transform属性进行平移变换,而不是直接去操作view的frame,这样做的好处是当我们要还原view的状态时可以直接将transform重置为0,而不需要再关心计算下移时的距离。
    • 还原(下移至原始状态)
      根据前面所说,我们只要在恰当的时机操作view的transform属性就可以实现了。
    - (void)keyboardWillShow:(NSNotification *)notification
    {
        //获取处于焦点中的view
        NSArray *textFields = @[phoneNemberText, verifyCodeText];
        UIView *focusView = nil;
        for (UITextField *view in textFields) {
            if ([view isFirstResponder]) {
                focusView = view;
                break;
            }
        }
        if (focusView) {
            //获取键盘弹出的时间
            double duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
            //获取键盘上端Y坐标
            CGFloat keyboardY = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;
            //获取输入框下端相对于window的Y坐标
            CGRect rect = [focusView convertRect:focusView.bounds toView:[[[UIApplication sharedApplication] delegate] window]];
            CGPoint tmp = rect.origin;
            CGFloat inputBoxY = tmp.y + focusView.frame.size.height;
            //计算二者差值
            CGFloat ty = keyboardY - inputBoxY;
            NSLog(@"position keyboard: %f, inputbox: %f, ty: %f", keyboardY, inputBoxY, ty);
            //差值小于0,做平移变换
            [UIView animateWithDuration:duration animations:^{
                if (ty < 0) {
                    self.view.transform = CGAffineTransformMakeTranslation(0, ty);
                }
            }];
        }
    }
     
    - (void)keyboardWillHide:(NSNotification *)notification
    {
        //获取键盘弹出的时间
        double duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        //还原
        [UIView animateWithDuration:duration animations:^{
            self.view.transform = CGAffineTransformMakeTranslation(0, 0);
        }];
    }
    

    看上去这样已经完美实现了输入框随键盘自动上移,我们也可以喝杯茶稍微休息一下了。没错,在iOS 8及之后的系统中,确实可以正常的工作,然而如果你的应用需要适配iOS 7并且要支持横屏,那么上面的方式在iOS7上,并不能按照我们的期望正确移动。
    原因:在ios7上,键盘的frame,系统是按照竖屏状态下window坐标系来计算的,并不考虑旋转的因素,因此在横屏下得到的键盘frame是错误的。受此影响的还有横屏时获取屏幕宽高[UIScreen mainScreen].bounds,也会有这样的问题。这种情况我们不仅无法正确得到键盘的frame,而且输入框相对于window的坐标计算结果也是错误的。
    因此在ios7上,键盘上端的Y坐标以及输入框下端相对于window的Y坐标需要单独处理。键盘上端的Y坐标可以通过屏幕高度减键盘高度得到。我们通过下面的方法获取键盘上端的Y坐标。

    - (CGFloat)getKeyboardY:(NSDictionary *)userInfo
    {
        CGFloat screenHeight;
        CGFloat keyboardY = 0;
        CGFloat keyboardHeight = 0;
        UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
        if (( [[[UIDevice currentDevice] systemVersion] floatValue]<8)  && UIInterfaceOrientationIsLandscape(orientation))
        {
            screenHeight = [[UIScreen mainScreen] bounds].size.width;
            keyboardHeight = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.width;
            keyboardY = screenHeight - keyboardHeight;
        }
        else if (( [[[UIDevice currentDevice] systemVersion] floatValue]<8)  && UIInterfaceOrientationIsPortrait(orientation)) {
            screenHeight = [[UIScreen mainScreen] bounds].size.height;
            keyboardHeight = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
            keyboardY = screenHeight - keyboardHeight;
        }
        else {
            keyboardY = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;
        }
        return keyboardY;
    }
    

    输入框下端相对于window的坐标如何计算呢?我们首先获得的其实是基于竖屏状态下坐标系中的Y值,而我们期望的是横屏下得到横屏状态下坐标系中的Y值,根据两个坐标系的关系,可以将第一次转换得到的坐标再做一次转换,计算得出横屏坐标系下的Y坐标值。我们通过下面的方法获取输入框下端的Y坐标。

    - (CGPoint)getViewOriginPointToWindow:(UIView *)view
    {
        CGPoint origin;
        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8) {
            CGPoint focusViewPoint = [view convertPoint:CGPointZero toView:nil];
            UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
            if (orientation == UIInterfaceOrientationLandscapeLeft) {
                origin.y = focusViewPoint.x;
                origin.x = [[[UIApplication sharedApplication] delegate] window].bounds.size.height - focusViewPoint.y;
            }
            else if (orientation == UIInterfaceOrientationLandscapeRight) {
                origin.y = [[[UIApplication sharedApplication] delegate] window].bounds.size.width - focusViewPoint.x;
                origin.x = focusViewPoint.y;
            }
            else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
                origin.y = [[[UIApplication sharedApplication] delegate] window].bounds.size.height - focusViewPoint.y;
                origin.x = [[[UIApplication sharedApplication] delegate] window].bounds.size.width - focusViewPoint.x;
            }
            else {
                origin = focusViewPoint;
            }
        }
        else {
            CGRect rect = [view convertRect:view.bounds toView:[[[UIApplication sharedApplication] delegate] window]];
            origin = rect.origin;
        }
        return origin;
    }
    

    因此我们将之前获取两个Y坐标的代码改用下面的方式:

    //获取键盘上端Y坐标
    CGFloat keyboardY = [self getKeyboardY:notification.userInfo];
    //获取输入框下端相对于window的Y坐标
    CGPoint tmp = [self getViewOriginPointToWindow:focusView];
    CGFloat inputBoxY = tmp.y + focusView.frame.size.height;
    

    这样就完美实现了输入框随键盘自动上移的效果。

    测试页面

    相关文章

      网友评论

      • kongkk:楼主这个方法不会再切换键盘的时候出现问题吗?比如先是手写键盘,然后切换成搜狗第三方键盘,输入框的移动会变得很奇怪。
      • peal:多谢楼主分享 不过 keyboardHeight = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.width; 这里的userInfo 获取 可能没做说明 NSDictionary *userInfo = [notification userInfo];

      本文标题:iOS 实现输入框跟随键盘自动上移

      本文链接:https://www.haomeiwen.com/subject/dkgmattx.html