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

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

部分页面需要显示一个工具栏,当键盘出现时,这个工具栏显示在键盘上方。由于使用了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;
    }
   
}
目录
相关文章
|
Go Android开发
autojs发送通知修改图标
牙叔教程 简单易懂
601 0
|
2月前
|
iOS开发
个推发送消息各字段在系统状态栏显示的信息,点击消息图标激活应用传递的信息,应用在线收到的透传消息信息
个推发送消息各字段在系统状态栏显示的信息,点击消息图标激活应用传递的信息,应用在线收到的透传消息信息
24 0
|
2月前
|
开发者
在用户关闭页面时,提示用户有内容未保存-论onbeforeunload事件的用法
在用户关闭页面时,提示用户有内容未保存-论onbeforeunload事件的用法
45 0
|
JSON 小程序 JavaScript
【小程序】页面事件
【小程序】页面事件
131 0
【小程序】页面事件
|
Web App开发 前端开发 API
你知道关闭页面时怎么向后台发送消息吗?
这两天碰到一个需求:在用户刷新页面或者关闭页面的时候,前端要给后台发一条请求,释放该页面的授权占用。
179 0
你知道关闭页面时怎么向后台发送消息吗?
SAP 操作,弹出报错 - 已根据规则拒绝服务器触发的操作,是否要查看上个通讯步骤中触发的操作列表 -
SAP 操作,弹出报错 - 已根据规则拒绝服务器触发的操作,是否要查看上个通讯步骤中触发的操作列表 -
SAP 操作,弹出报错 - 已根据规则拒绝服务器触发的操作,是否要查看上个通讯步骤中触发的操作列表 -
UI5应用如果出现白屏但是没有任何错误消息打印出来,应该如何处理
UI5应用如果出现白屏但是没有任何错误消息打印出来,应该如何处理
UI5应用如果出现白屏但是没有任何错误消息打印出来,应该如何处理
|
C#
【C#】解决MouseHook捕获鼠标动作,在有些电脑上SetWindowsHookEx失败返回0的问题
原文:【C#】解决MouseHook捕获鼠标动作,在有些电脑上SetWindowsHookEx失败返回0的问题 最近在debug鼠标位置捕获的功能时发现在其中的一台开发电脑上,SetWindowsHookEx一直返回0,导致Hook设置失败,有时候调成Release模式又是正常的。
1268 0