如何解决由引起的IQKeyboardManager部分页面返回的键盘高度比实际小或最后收到键盘隐藏通知却显示了键盘问题

洪博涛
2023-12-01

部分页面需要显示一个工具栏,当键盘出现时,这个工具栏显示在键盘上方。由于使用了IQKeyboardManager,导致有的页面iOS12.5.6系统的手机出现首次键盘高度比实际低44像素,而iOS14.7.1系统的手机出现首次键盘高度比实际低44像素并且有时出现最后收到键盘隐藏通知但是实际显示了键盘。
收到通知直接设置工具栏的frame,也过于突兀,最好采用做动画的方式显示工具栏,动画完成时再修正键盘高度,这样能部分解决上面的那两个问题。
那键盘的动画时间是0.25秒,可以在键盘通知里获取到这个参数。那键盘的实际高度从哪里获取呢?经过观察View UI Herarchy发现有键盘的页面都有UIInputSetContainerView,键盘的总高度就是UIInputSetHostView的总高度。只是iOS13及跟高的系统,键盘是在第二个窗口的UIInputWindowController中,而比iOS13低的版本在第是哪个窗口的UITextEffectsWindow中。具体的实现如下:
增加键盘显示通知:

        //监听键盘的变化
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardChange:) name:UIKeyboardWillShowNotification object:nil];

键盘通知处理:

- (void)keyBoardChange:(NSNotification *)notification {
    //获取键盘的高度
        NSDictionary *userInfo = [notification userInfo];
        NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
        CGRect keyboardRect = [aValue CGRectValue];
        CGFloat height = keyboardRect.size.height;
    //获取动画时间I
    CGFloat animationDuration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    NSLog(@"animationDuration:%f,height:%f",animationDuration,height);
    

    if(self.keyBoardChangeBlock)
    {
        self.keyBoardChangeBlock(height, animationDuration);
    }
}

键盘显示动画与修正:

- (LCCommentToolView *)comTool {
    if (_comTool == nil) {
        _comTool  = [[LCCommentToolView alloc] initWithFrame:CGRectMake(0, 0, KScreenW, BaseSize(100))] ;
        [_comTool setCorner:UIRectCornerTopLeft|UIRectCornerTopRight cornerSize:BaseSize(15) forRect:CGRectMake(0, 0, KScreenW, BaseSize(100))];
        DYWeakSelf;
        [_comTool setKeyBoardChangeBlock:^(CGFloat height, CGFloat animationDuration) {
            if (DYGlobleData.isLogin) {
                if(animationDuration <= 0)
                {
                    //防范式编程,理论不会出现
                    weakSelf.bgV.hidden = NO;
                }
                else
                {
                    weakSelf.bgV.hidden = (height<=0);
                    [UIView animateWithDuration:animationDuration animations:^{
                        if((height<=0))
                        {
                            [weakSelf.comTool mas_updateConstraints:^(MASConstraintMaker *make) {
                                make.height.mas_equalTo(BaseSize(100));
                                make.width.mas_equalTo(KScreenW);
                                make.bottom.mas_equalTo(BaseSize(100) -(49+(BR_BOTTOM_MARGIN?24:0)));
                            }];
                            [weakSelf.comTool updateCommentTVWithShift:(BaseSize(100) -(49+(BR_BOTTOM_MARGIN?24:0))+(BR_BOTTOM_MARGIN?24:0))];
                        }
                        else
                        {
                            [weakSelf.comTool mas_updateConstraints:^(MASConstraintMaker *make) {
                                make.height.mas_equalTo(BaseSize(100));
                                make.width.mas_equalTo(KScreenW);
                                make.bottom.mas_equalTo(-height);
                            }];
                            [weakSelf.comTool updateCommentTVWithShift:0];
                        }
                        [weakSelf layoutIfNeeded];
                    } completion:^(BOOL finished) {
                        CGFloat keyboardHeight = [weakSelf displayKeyboardDockView];
                        if(keyboardHeight > 0)
                        {
                            [weakSelf.comTool mas_updateConstraints:^(MASConstraintMaker *make) {
                                make.height.mas_equalTo(BaseSize(100));
                                make.width.mas_equalTo(KScreenW);
                                make.bottom.mas_equalTo(-keyboardHeight);
                            }];
                            [weakSelf.comTool updateCommentTVWithShift:0];
                        }
                        else
                        {
                            [weakSelf.comTool mas_updateConstraints:^(MASConstraintMaker *make) {
                                make.height.mas_equalTo(BaseSize(100));
                                make.width.mas_equalTo(KScreenW);
                                make.bottom.mas_equalTo(BaseSize(100) -(49+(BR_BOTTOM_MARGIN?24:0)));
                            }];
                            [weakSelf.comTool updateCommentTVWithShift:(BaseSize(100) -(49+(BR_BOTTOM_MARGIN?24:0))+(BR_BOTTOM_MARGIN?24:0))];
                        }
                        [weakSelf layoutIfNeeded];
                    }];
                }
            } else {
                weakSelf.bgV.hidden = YES;
                [weakSelf.comTool mas_updateConstraints:^(MASConstraintMaker *make) {
                    make.height.mas_equalTo(BaseSize(100));
                    make.width.mas_equalTo(KScreenW);
                    make.bottom.mas_equalTo(BaseSize(100) -(49+(BR_BOTTOM_MARGIN?24:0)));
                }];
                [weakSelf.comTool updateCommentTVWithShift:(BaseSize(100) -(49+(BR_BOTTOM_MARGIN?24:0))+(BR_BOTTOM_MARGIN?24:0))];
            };
        }];
    }
    return _comTool;
}

识别键盘是否在显示和获取键盘高度,键盘高为0.0是键盘隐藏:

- (CGFloat)displayKeyboardDockView{
    UIWindow *keyboardWindow = [[[UIApplication sharedApplication] windows] objectAtSafeIndex:1];
    UIView *keyboardContainerView;
    UIView *keyboardHostView;
 
    if (@available(iOS 13.0, *))
    {
        for(int i = 0; i < [keyboardWindow.subviews count]; i++) {
            keyboardContainerView = [keyboardWindow.subviews objectAtIndex:i];
            UIViewController *nextResponder = (UIViewController*)[keyboardContainerView nextResponder];
            if(([nextResponder isKindOfClass:NSClassFromString(@"UIWindow")]))
            {
                NSLog(@"[nextResponder.subviews count]:%d, nextResponder.subviews:%@", [keyboardWindow.subviews count], keyboardWindow.subviews);
            }
            //寻找keyboardWindow层的UIInputWindowController
            else if ([nextResponder isKindOfClass:NSClassFromString(@"UIInputWindowController")]) {
                for(int y = 0; y < [nextResponder.view.subviews count]; y++) {
                    //寻找UIInputWindowController层的UIInputSetContainerView
                    if([[keyboardContainerView description] hasPrefix:@"<UIInputSetContainerView"] == YES){
                        for(int t = 0; t < [keyboardContainerView.subviews count]; t++) {
                            keyboardHostView = [keyboardContainerView.subviews objectAtIndex:t];
                            //寻找UIInputSetContainerView层的UIInputSetHostView
                            if([[keyboardHostView description] hasPrefix:@"<UIInputSetHostView"] == YES){
                                NSLog(@"keyboardHostView description:%@,keyboardHostView.isHidden:%d,[keyboardHostView.subviews count],[keyboardHostView.subviews count],keyboardHostView.frame.size.height:%f,keyboardHostView.frame.origin.y:%f, (keyboardHostView.frame.origin.y == [[UIScreen mainScreen] bounds].size.height):%d", [keyboardHostView description],keyboardHostView.isHidden,[keyboardHostView.subviews count], keyboardHostView.frame.size.height,keyboardHostView.frame.origin.y, (keyboardHostView.frame.origin.y == [[UIScreen mainScreen] bounds].size.height));
                                if (lroundl(keyboardHostView.frame.origin.y) != lroundl(([[UIScreen mainScreen] bounds].size.height)))
                                {
                                    return keyboardHostView.frame.size.height;
                                }
                                else
                                {
                                    return 0.0;
                                }
                            }
                        }
                    }
                }
            }
        }
        return 0.0;
    }
    else
    {
        keyboardWindow = [[[UIApplication sharedApplication] windows] objectAtSafeIndex:2];
        if(keyboardWindow && [keyboardWindow isKindOfClass:NSClassFromString(@"UITextEffectsWindow")] && !isCommonUnitEmptyArray(keyboardWindow.subviews))
        {
            keyboardContainerView = [keyboardWindow.subviews objectAtSafeIndex:0];
            if(keyboardContainerView && ([[keyboardContainerView description] hasPrefix:@"<UIInputSetContainerView"] == YES))
            {
                for(int t = 0; t < [keyboardContainerView.subviews count]; t++) {
                    keyboardHostView = [keyboardContainerView.subviews objectAtIndex:t];
                    //寻找UIInputSetContainerView层的UIInputSetHostView
                    if([[keyboardHostView description] hasPrefix:@"<UIInputSetHostView"] == YES){
                        NSLog(@"keyboardHostView description:%@,keyboardHostView.isHidden:%d,[keyboardHostView.subviews count],[keyboardHostView.subviews count],keyboardHostView.frame.size.height:%f,keyboardHostView.frame.origin.y:%f, (keyboardHostView.frame.origin.y == [[UIScreen mainScreen] bounds].size.height):%d", [keyboardHostView description],keyboardHostView.isHidden,[keyboardHostView.subviews count], keyboardHostView.frame.size.height,keyboardHostView.frame.origin.y, (keyboardHostView.frame.origin.y == [[UIScreen mainScreen] bounds].size.height));
                        if (lroundl(keyboardHostView.frame.origin.y) != lroundl(([[UIScreen mainScreen] bounds].size.height)))
                        {
                            return keyboardHostView.frame.size.height;
                        }
                        else
                        {
                            return 0.0;
                        }
                    }
                }
            }
        }
        return 0.0;
    }
   
}
 类似资料: