android ScollView 嵌套 WebView 底部空白,高度无法自适应解决

2018-10-21 22:29:24


毕竟webview要自适应的话的场景并不是很多,除非和原生一起使用,所以我选择了检测新的请求跳转新的webview。这样解决的。那个里面只有一个webview,网页自己滚动。


最近要做一个页面,需要 ScrollView 嵌套 WebView,怎么嵌套,怎么解决焦点和 touch 事件冲突,网上一大堆,这里就不赘述了,但是发现 WebView 从一个高度很高的网页加载一个高度很低的网页的时候,高度无法自适应了,造成底部会有一大片的空白,解决方案找到了挺多,描述一下:


Google 官方建议

  Google 建议不要在 ScrollView 中使用 WebView,但是毕竟无法避免,产品的需求;


移除重新添加新的 WebView

  每次加载新的 url 的时候 remove 掉旧的 WebView,重新加入一个新的 WebView 去加载这个新的 url,这种方案是可行的,但是毕竟不太好,效率不高,而且会造成体验上不太好;


JS 注入,获取页面内容高度,设置成 WebView 高度

  JS 注入,通过前端 JS 调用 native 方法,把高度值传递过来,然后通过 layoutparams 去设置 webview 的高度:


mWebView.setWebViewClient(new WebViewClient() {

    @Override

    public void onPageFinished(WebView view, String url) {

        mWebView.loadUrl("javascript:App.resize(document.body.getBoundingClientRect().height)");

        super.onPageFinished(view, url);

    }

});

mWebView.addJavascriptInterface(this, "App");

1

@JavascriptInterface

public void resize(final float height) {

    getActivity().runOnUiThread(new Runnable() {

        @Override

        public void run() {

            //Toast.makeText(getActivity(), height + "", Toast.LENGTH_LONG).show();

            //此处的 layoutParmas 需要根据父控件类型进行区分,这里为了简单就不这么做了

            mWebView.setLayoutParams(new LinearLayout.LayoutParams(getResources().getDisplayMetrics().widthPixels, (int) (height * getResources().getDisplayMetrics().density)));

        }

    });

}

1

2

3

4

5

6

7

8

9

10

11

需要注意的是上面的 resize 方法一定要上面那么写,写成:


mWebView.getLayoutParams().height = (int) (height * getResources().getDisplayMetrics().density);

1

这样是无法成功的,看来宽度也是有影响的


感谢 @imesong 同学,这段代码有亮点可以完善的地方:


mWebVew.setLayoutParam() 时,应该根据 WebView 父控件的类型,创建 LayoutParam,或者直接用 mWebView.getLayoutParams() 获取 LayoutParams;

调用 JAVA 方法的 JS ,可以在网页加载完成时自己加载下面这段 JS 代码(区别在于一个是终端处理,一个是前段处理),比如:

(function(w){

    window.App.resize(document.body.getBoundingClientRect().height);

})(window); 

1

2

3

加载这段 JS 就可以了,“APP” 和上面一样是自己注册是自己注册的接口名字; 

思路是一样的,处理方式有差异。 

试验不太成功的方式

  网上也找到了一些其他的方式,试了一下,不太成功,不知道是不是使用姿势的问题,感兴趣的也可以试试,反馈结果给我。


先加载一个空网页

  在从高网页加载低网页的时候,先加载一个空内容,接着立马做相关的处理操作(比如加载新的网页,更改字体等),


// load empty data to shrink the WebView instance

mArticleWebView.loadUrl(Constants.ASSETS_EMPTY);

// load real data

mArticleWebView.loadDataWithBaseURL(null,data,"text/html","utf-8",null);

1

2

3

4

Constants.ASSETS_EMPTY 仅仅只是一个 String 子串,标识该空网页的位置,所以该变量可以为 “file:///android_asset/Empty.html”. 

试了一下,也是不好用的,不知道是不是我的操作问题, 

原文链接 http://vision-apps.blogspot.hk/2012/08/android-webview-tips-tricks.html


修改 Setting 属性

wv.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);

wv.setVerticalScrollBarEnabled(false);

wv.setVerticalScrollbarOverlay(false);

wv.setHorizontalScrollBarEnabled(false);

wv.setHorizontalScrollbarOverlay(false);

1

2

3

4

5

一样不好用,原文链接http://blog.csdn.net/wht3xr/article/details/21004053


另外一些人的讨论

  一些人的讨论,比较有参考价值:http://stackoverflow.com/questions/15546416/how-to-shrink-webview-size-dynamically-according-to-its-content


总结

  综合考虑来看,第三种方式是比较合适的,我当时也是使用的第三种方式解决的这个问题。


  • 2019-05-18 12:40:35

    Android夜间模式的几种实现

    通过增加一层遮光罩来实现。效果不是很理想,但是好用,毕竟很多手机都有自己的夜间模式了

  • 2019-05-19 02:25:15

    php使用TCPDF生成PDF文件教程

    orientation属性用来设置文档打印格式是“Portrait”还是“Landscape”。 Landscape为横式打印,Portrait为纵向打印

  • 2019-05-21 11:46:05

    RecyclerView 加动画的坑

    然后加到recyclerView上,我是在adapter上加的。Adapter的holder复用相信大家也都很熟悉了,这个在绘制效率的提高上很重要,也很容易发现一个问题,就是内容混乱的复用。所以常见的处理就是对view加上tag来多次判断,对于visibility之类的设置一定是if...else的写法,光有if是不可以的。

  • 2019-05-21 11:54:10

    Android中如何设置字体大小

    首先要强调一点,某些用户可能存在视力障碍甚至几近失明,他们无法顺利阅读一般尺寸下的文字内容。Android操作系统意识到了这些情况,并提供了一套显示辅助功能,使得用户可以根据自己的使用习惯随意缩放设备中文本字体的大小。 要在设备上修改字体设定,首先启用“设定”应用,然后选择“显示”项下的“字体尺寸”。用户可以在设备预置的四种文本字体尺寸中选择适合自己的方案(包含小、正常、大、超大),详见图一。

  • 2019-05-21 12:34:38

    浅谈Recycleview嵌套卡顿 以及你所不知道的解决方案

    由于项目需要,需要做到recycleview 这里先不讲如何用其他控件代替这种嵌套的方式 先假定你已经嵌套了 老板还不给时间给你给布局方式 那么这个时候你的这个嵌套列表 必定是卡顿的 只要超过一屏,展示效果会有卡顿现象,原因就是由于两个RecyclerView的存在,使得滑动的view滑出当前屏幕的释放存在冲突

  • 2019-05-21 12:35:54

    RecyclerView setHasFixedSize(true)的意义

    设置为true,再调用notifyDataSetChanged(),发现大小重新计算了,看来理解出现错误了。还是再看一下哪些地方用到这个mHasFixedSize吧。

  • 2019-05-21 12:37:34

    RecyclerView 刷新闪烁

    闪烁是 notifyDataSetChange 造成的。由于适配器不知道整个数据集中的哪些内容已经存在,在重新匹配 ViewHolder 时发生的。 当然,遇到这个问题时有去搜索一些答案,看到的很多都是去禁止 RecycleView 的默认动画,可惜这对我没什么用。下面的方法是对我有用的。

  • 2019-05-21 12:43:26

    (重要)RecycleView的缓存机制

    RecycleView的四级缓存是由三个类共同作用完成的,Recycler、RecycledViewPool和ViewCacheExtension。Recycler用于管理已经废弃或者与RecyclerView分离的ViewHolder,这里面有两个重要的成员,为可以看见的屏幕的内部缓存成员mAttachedScrap、mChangedScrap和滑出屏幕外的外部缓存成员mCachedViews二者共同完成ViewHolder的缓存;RecycledViewPool类是用来缓存整体所有的ViewHolder,是对mCachedViews缓存的补充;ViewCacheExtension是扩展内的缓存对象,默认不加载,需实现方法getViewForPositionAndType(Recycler recycler, int position, int type)来实现自己的缓存。接下来对四级缓存一步步介绍。