UIWebView 键盘事件的处理思路以及方法

iOS 同时被 2 个专栏收录
59 篇文章 0 订阅
2 篇文章 0 订阅

在 iOS 的项目中,经常会遇到内嵌网页的场景,而网页内的输入框也比较常见。一般来说,键盘的弹起事件和防止遮挡输入框是由前端同学处理的,但可能因为种种原因,这个锅可能甩到我们 iOS 工程师身上。
锅从天而降,不接也没法。那就逆向思维,分析一下具体的实现思路吧:


期望结果: 键盘弹出后,webView 需要上移某一个距离,保证不遮挡输入框。(如何获取正确的距离?)

获取距离: 计算输入框距离屏幕底部和键盘高度之间的差值。(输入框在 WebView 中,如何获取?)

获取输入框的位置: 给视图添加一个全屏的点击手势,点击输入框的时候,通过坐标转换,计算出相对屏幕的点击坐标。(但点击位置并不一定是输入框的底部,所以键盘弹出后依然会遮住一部分输入框,获取 WebView 输入框的高度即可)

获取输入框的高度: 通过注入一段获取输入框高度的 JS 代码,来尝试获取 input 元素的高度。


有了方案,就开始动手吧…

一、基础准备
添加点击手势 ,监听系统键盘弹出事件, 并禁调 WebView 键盘弹出事件。

- (void)loadView{
    [super loadView];
    
    UITapGestureRecognizer *webTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(webTap:)];
    webTap.delegate = self;
    webTap.cancelsTouchesInView = NO;
    [self.view addGestureRecognizer:webTap];

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

#pragma mark - UIGestureRecognizerDelegate
//允许多个手势识别器共同识别
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}

//禁止网页键盘的响应
- (UIView*)viewForZoomingInScrollView:(UIScrollView*)scrollView{
    return nil;
}

二、捕捉点击事件,进行坐标转换
考虑到网页里底部输入框的情况,默认会避开安全区,所以做一个DefineBlankHeight(34) 的宽容机制。

- (void)webTap:(UITapGestureRecognizer *)sender{
    CGPoint tapPoint = [sender locationInView:self.view];
    CGPoint convertPoint = [self.view.window convertPoint:tapPoint fromView:self.view];
    self.gapHeight = SCREEN_HEIGHT - convertPoint.y - DefineBlankHeight;
}

三、JS 注入
网页加载完成的时候注入 JS 方法

- (void)webViewDidFinishLoad:(UIWebView *)webView{
    NSString *js = @"function getInputHeight() { \
    return document.activeElement.style.height;\
    }";
    NSString *result= [webView stringByEvaluatingJavaScriptFromString:js];
    NSLog(@"%@",result);
}

这里需要说明一下,通过document.activeElement.style.height只能获取到标签的内部属性,比如:

<input type="text" id="msg-area" style="width:80%;height:25px;">

但对于下面这种:

.textfield {
	height: 50px;
	color: #00FF00;
	font-size: 16px;
}
<input class="textfield" type="text" name="submit" value="1" class="text1"><br>

就获取不到了,具体方法还得请教一下前端的小老弟。

四、实现键盘监听的方法

// 调用注入的 js 方法,获取到输入框高度
-(void)inputTapAction{
    NSString *result =  [self.webView  stringByEvaluatingJavaScriptFromString:@"getInputHeight()"];
    NSLog(@"inputTapAction  %@",result);
    self.inputHeight = [[result componentsSeparatedByString:@"px"].firstObject intValue];
    //如果获取不到,给一个默认值。
    if (self.inputHeight == 0) {
        self.inputHeight = 35;
    }
}
//键盘将要出现
- (void)keyboardWillShow:(NSNotification *)notification {
    [self inputTapAction];
    NSDictionary *userInfo = [notification userInfo];
    NSValue* value = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardRect = [value CGRectValue];
    
    CGFloat finalHeight = keyboardRect.size.height - self.gapHeight + self.inputHeight;
    
    [self.webView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.top.inset(-finalHeight);
        make.bottom.inset(finalHeight);
    }];
    
    CGFloat keyboardDuration =
    [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration:keyboardDuration animations:^{
        [self.webView.superview layoutIfNeeded];
    }];
}

//键盘将要消失
- (void)keyboardWillHide:(NSNotification *)notification {
    [self.webView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.top.inset(0);
        make.bottom.inset(0);
    }];
    NSDictionary *userInfo = [notification userInfo];
    CGFloat keyboardDuration =
    [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration:keyboardDuration animations:^{
        [self.webView.superview layoutIfNeeded];
    }];
}

最后,别忘了移除观察

- (void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

总结:主要原理是就是通过输入框相对屏幕位置和键盘之间的高度差,来改变 webView 的 frame。核心代码就是手势的穿透、坐标转换 和 js 方法的注入。

  • 2
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

江枫夜雨

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值