在日常开发过程中,有时候会遇到需要在app中嵌入网页,WebView加载数据(不是加载网址)的时候,此时使用WebView实现效果,但在默认情况下是无法点击图片查看大图的,更无法保存图片。本文将就这一系列问题的实现进行说明。
这里面主要还是用到了android原生和js交互的知识、js添加事件的知识。
1、首先在andorid的页面中获取到html的字符串(bean.getContent()),然后在调用公共方法去获取到网页中的所有图片数组集合。之后就是android原生与js交互的规则了,如你所见,此处不再详细介绍。
//这两行copy出来,这个变量是WebView设置和js交互时设置的名称,可以随意起,js调用的时候也用这个就可以了 String JSCALLJAVA = "jsCallJavaObj"; String method = JSCALLJAVA; String[] imgs = returnImageUrlsFromHtml(webContent); mWebSettings = webView.getSettings(); mWebSettings.setJavaScriptEnabled(true); webView.addJavascriptInterface(new ImageJavascriptInterface(mContext, imgs), method); webView.setWebViewClient(new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); setWebImageClick(view, method); } }); String webContent=bean.getContent(); //WebView加载数据代码 webView.loadDataWithBaseURL(null, webContent, "text/html", "utf-8", null);
获取图片数组的方法,通过正则匹配来获取:
public String[] returnImageUrlsFromHtml(String htmlCode) { List<String> imageSrcList = new ArrayList<String>(); Pattern p = Pattern.compile("<img\\b[^>]*\\bsrc\\b\\s*=\\s*('|\")?([^'\"\n\r\f>]+(\\.jpg|\\.bmp|\\.eps|\\.gif|\\.mif|\\.miff|\\.png|\\.tif|\\.tiff|\\.svg|\\.wmf|\\.jpe|\\.jpeg|\\.dib|\\.ico|\\.tga|\\.cut|\\.pic|\\b)\\b)[^>]*>", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher(htmlCode); String quote = null; String src = null; while (m.find()) { quote = m.group(1); src = (quote == null || quote.trim().length() == 0) ? m.group(2).split("//s+")[0] : m.group(2); imageSrcList.add(src); } if (imageSrcList.size() == 0) { return null; } return imageSrcList.toArray(new String[imageSrcList.size()]); }
接下来是android原生和js交互的代码:
(1) Java类(定义的内部类),js会通过之前设置的名称method来调用到其中的方法
class ImageJavascriptInterface { private Context context; private String[] imageUrls; public ImageJavascriptInterface(Context context, String[] imageUrls) { this.context = context; this.imageUrls = imageUrls; } //java回调js代码,不要忘了@JavascriptInterface这个注解,不然点击事件不起作用 @JavascriptInterface public void openImage(String img, int pos) { Log.i(TAG, "img*****" + img); Log.i(TAG, "pos*****" + pos);
//保存图片操作(根据需求,可能是先弹框,然后保存图片) initSavaPicture(img); } }
(2)这段代码是在onPageFinished网页加载完成之后设置的,其中主要是添加了一段js代码,只有在网页加载完成之后,才能从dom中获取所有的img节点也就是图片。至于本身前端写的html中并没有给img添加点击的事件,所以我们来动态给他添加进去。
一般h5和原生交互,这段代码可以直接h5来写,你将你设置的java方法和起的名字告诉h5让其写进去就可以(具体到下面代码中就是method和openImage方法)
/** * 设置网页中图片的点击事件 * * @param view * @param method */ public void setWebImageClick(WebView view, String method) { String jsCode = "javascript:(function(){" + "var imgs=document.getElementsByTagName(\"img\");" + "for(var i=0;i<imgs.length;i++){" + "imgs[i].pos = i;" + "imgs[i].οnclick=function(){" + "window." + method + ".openImage(this.src,this.pos);" + "}}})()"; view.loadUrl(jsCode); }
(3)这时候图片可以直接保存了,但是如果是
androidx.core.widget.NestedScrollView或者ScrollView嵌套WebView的时候,
第一次点击图片,WebView会有自动滑动一下的bug,解决这个问题。
可能是WebView抢占了焦点而导致的自动滚动,于是就在WebView的父布局(LinearLayout)加了一行:
android:descendantFocusability="blocksDescendants"
就解决了这个自动滑动一下的bug。
descendantFocusability有几个属性如下:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
我们需要的是让父类Layout(LinearLayout)直接覆盖子类Layout(WebView)直接获取到焦点,这样WebView就不会自动滑动了。
如对此有疑问,请联系qq1164688204。
推荐Android开源项目
项目功能介绍:RxJava2和Retrofit2项目,添加自动管理token功能,添加RxJava2生命周期管理,使用App架构设计是MVP模式和MVVM模式,同时使用组件化,部分代码使用Kotlin,此项目持续维护中。
项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2