WebView高度自适应方案探究

Android项目开发中针对webview避免不了混合开发模式,可Android上的webview又很不争气,几乎每个Android版本都有webvie的改动,在国内这种鱼龙混杂环境下出乎意料的问题又很多,这次就谈谈webview高度自适应的问题。

问题

在Android开发生涯中想必大家都遇到过,webview在有些时候展示不完整,在某些时候底部有一片空白,有些时候始终又滑不到底。。。导致这个问题的原因常见有以下三种:

  • 网页高度不固定
  • 嵌套布局导致webview的高度无法自适应
  • 系统原因导致webview在某种特殊情况下不能兼容当前应用的屏幕分辨率

下边就分别说说这三种情况引起的原因以及解决方法。

针对网页高度不固定问题

这部分原因和H5编写方法有很大关系,例如Ajax异步处理结果过慢,webview的高度不能及时更新;也有可能H5编写时预留了一个资源展示区等待将来资源展示,结果资源没有加载出来。这个和H5开发人员说明一下情况,检查一下代码结构。

针对嵌套布局导致webview高度不固定问题

这个是Android开发最常见的事,很多时候是混合开发模式,不得已采用scrollview嵌套webview,但是我们知道scrollview中嵌套其他view常常使某些view的高度(match_parent)失效,当然你可以采用android:fillViewport="true"强制让其撑满,但是似乎其内部的webview又不听话了,这个道理很明显,毕竟webview渲染的是网页,也即是我们能够准确固定webview高度这个问题就迎刃而解了。

针对webview兼容当前应用屏幕密度问题

首先我们要处理的是避免系统字体的缩放影响webview缩放,我们可以用webview.getSettings().setTextZoom(100)来避免。其余的支持自适应即可,在应用屏幕密度设定之后webiview可自动匹配,当然也有一些奇葩设备(被应用商修改过),这部分我们可以忽略了。

针对高度不固定问题解决方案

我这里给出两种解决方案。

布局结构调整

按照官方建议webiview父布局高度采用match_parent

WebView根据网页的高度自动扩展自身高度:

我们按照步骤走:

第一步:本地定义Js交互接口,通常H5需要明确这个接口标识,Android端才能回调相关内容给H5。

mWebView.addJavascriptInterface(this, "App");

第二步:本地实现接口方法,H5通过上边的“APP”接口标识能调用本地该接口里面的方法。

/**
 * js回调,重新计算webview的高度。
 */
@JavascriptInterface
public void resize(final float clientWidth, final float scrollHeight) {
    if (mActivity == null || mWebView == null || clientWidth == 0) {
        return;
    }
    mActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            float rate = mWebView.getWidth() / clientWidth;
            Log.i("TAG", "webview---------clientWidth:" + clientWidth + "---------scrollHeight:" + scrollHeight + "---------rate:" + rate);
            mWebView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                    (int) (scrollHeight * rate)));
        }
    });
}

第三步:本地调用H5的js方法,告诉H5:“我,大Android,需要你H5现在的宽和高”,然后H5乖乖的把界面上宽高回调给本地,就是第二步的方法。但是!我今天说的这个是通用方式,是针对所有的H5的,不可能让每个H5都定义一个js方法供Android端调用,怎么办呢?好办,直接让H5回调本地方法:

mWebView.loadUrl("javascript:App.resize(document.documentElement.clientWidth, document.documentElement.scrollHeight)");

这里的“App”其实就是“this”,那么js回调时机是什么时候呢,我是希望这个页面加载结束的时候告诉我,所以重写WebViewClient里面的onPageFinished方法。由于有些H5采用异步加载的方式,我不知道他到底什么时候完全加载出来,所以这里我分多次让H5帮我回调:

class DefaultWebViewClient extends WebViewClient {

    //页面内跳转
    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String s) {
        webView.loadUrl(s);
        return true;
    }

    @Override
    public void onPageFinished(WebView webView, String s) {
        super.onPageFinished(webView, s);

        //执行网页高度获取,不断获取网页高度
        mHandler.post(new Runnable() {

            //执行最大次数
            int times = 5;

            @Override
            public void run() {
                if (times > 0) {
                    mWebView.loadUrl("javascript:App.resize(document.documentElement.clientWidth, document.documentElement.scrollHeight)");
                    mHandler.postDelayed(this, 1000);
                    times--;
                }
            }
        });
    }
}

总结

以上是我针对该类问题想到的一些处理方案,大家有更好的处理方式不妨也分享一下,集思广路,一同进步。

我是i猩人,总结不易,转载注明出处,喜欢本篇文章的童鞋欢迎点赞、关注哦。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
对于UITableViewCell中包含WebView自适应高度问题,一般的解决方案是在webViewDidFinishLoad方法中计算WebView高度,并更新UITableViewCell的高度。但是这种方法有时会出现计算不准确的情况,以及性能问题。 最新的解决方案是使用iOS 11中引入的UITableViewAutomaticDimension,结合约束自动布局来实现UITableViewCell的自适应高度。具体步骤如下: 1. 在Storyboard或XIB中,设置UITableViewCell的约束,包括WebView的顶部、底部、左右两侧的约束,并将WebView高度设置为大于等于0的值(可以是一个较小的值,比如10)。 2. 在tableView(_:cellForRowAt:)方法中,设置WebView的代理为当前的UITableViewCell,并在webView(_:didFinish:)方法中更新UITableViewCell的高度: ```swift func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // 计算WebView的内容高度 webView.evaluateJavaScript("document.readyState") { (result, error) in if result != nil { webView.evaluateJavaScript("document.body.offsetHeight", completionHandler: { (height, error) in if let height = height as? CGFloat { // 更新UITableViewCell的高度 self.heightConstraint.constant = height self.setNeedsUpdateConstraints() self.updateConstraintsIfNeeded() self.layoutIfNeeded() self.delegate?.didUpdateHeight() } }) } } } ``` 3. 在tableView(_:estimatedHeightForRowAt:)方法中,返回一个估算的高度(可以是一个较小的值,比如100): ```swift func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return 100 } ``` 4. 在tableView(_:heightForRowAt:)方法中,返回UITableViewAutomaticDimension: ```swift func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableViewAutomaticDimension } ``` 注意:在使用约束自动布局的情况下,需要保证UITableViewCell的高度约束是完整的,即顶部和底部都有约束,否则自适应高度可能会出现问题。同时,在更新UITableViewCell的高度时,需要调用setNeedsUpdateConstraints、updateConstraintsIfNeeded和layoutIfNeeded方法,以保证约束的更新及时生效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值