# 03 - 点击网页图片查看大图 ### 前言 在写文章的时候,经常会用到图片,图片可以更加直观的表达一些文字难以表述的问题,也更加吸引人们的注意力。在开发 diycode 客户端的时候也考虑到了文章图片的问题,由于 Android 设备屏幕很小,对于某些高清大图来说,放在这么小的屏幕上很难看清楚,所以我就考虑点击图片的时候给用户展示一个可以缩放查看的大图。 为了比较完美的实现这一个功能,我进行了很多的尝试,最终得到了一个相对比较满意的结果,如下: ![](https://ww1.sinaimg.cn/large/006tNbRwly1fdqzpg6zdgg308c0ethdu.gif) ### 解决方案 上图效果是,点击的时候显示当前图片的大图,并且可以左右滑动查看文章中的所有图片,为了完成上图所示的效果,有两点内容比较重要: 1. 找到网页中所有图片 2. 监听当前被点击的图片 由于试验过程中坑比较多,所以先放解决方案了。 #### 1. 注入 JS 代码 为了完成这一功能,我给 WebView 注入了一段 JS 代码,如下: ```java @SuppressLint({"JavascriptInterface", "AddJavascriptInterface"}) private void addImageClickListener(Web webView) { // 遍历所有图片,并添加 onclick 函数,函数的功能是在图片点击的时候调用本地java接口并传递url过去 webView.loadUrl("javascript:(function(){" + "var objs = document.getElementsByTagName(\"img\"); " + "for(var i=0;i` 标签,当点击图片等时候会触发 Client 的 `shouldOverrideUrlLoading` 方法,在这了获取到链接,并且判断是不是图片,如果是图片则拦截下来,跳转到对应的显示图片的 Activity。 **那么问题来了,我们如何判断一个 url 请求是不是图片呢?** 最简单的办法就是判断后缀,通常的图片链接都是下面这样的: ``` http://xxxxx.xxx/xxxxx.png ``` 通过后缀可以很容易判断,但是当我测试的时候发现一篇文章的图片并不会被识别出来,于是我用 log 打印出来图片链接发现居然是这样子的: ``` https://user-gold-cdn.xitu.io/2017/3/16/16009283e2dc665b39f99d36d41d0ce7 (这是个 gif) https://user-gold-cdn.xitu.io/2017/3/16/4e820744d74e0c6e9f5076638d122d29 (这是个 jpg) ``` 当时我的内心一万匹羊驼飞奔而过,WTF,居然有图床不带后缀的,这对于网页当然不是问题,不仅有 `` 标签,请求的时候还会返回一个 ContentType 来确定类型。 而对于我这种方案来说就是晴天霹雳了,于是仅通过 url 过滤图片计划就这样失败了。 #### 坑二:图片超链接 由于第一种方案失败了,接连引发了第二个坑,就是文章中某些图片本身是带有超链接的,这些图片本身作用就是一种跳转提示,像一些 GitHub 的标签等,作用相当于一个 Button,在我使用的第一种方案中,是不会修改这些本身就已经有超链接的图片的,所以并不会影响,但是如果是使用注入 JS 的方式,当图片本身存在超链接时,点击图片则会触发两次跳转,第一次跳转是跳转到超链,第二次是图片的点击事件。所以会打开两个 Activity。这显然是不符合逻辑的。 我想要的效果时,如果图片本身不带超链接则打开大图,带有超链接则默认跳转,所以我又思索了好久对逻辑进行了修改。 在加载文章之前,为所有不带超链接的图片添加一个标记 `class="gcs-img-sign"` 之后根据这个标记来为图片添加点击事件,这样带有超链接的图片就不会受到影响了。 当然了,这种方案的前提是能拿到网页需要加载内容的源码,如果仅仅是一个 url 的话就会比较麻烦了。 #### 坑三:WebView 问题 最初在测试注入 JS 代码的时候一直不能成功,总是报出一些异常,经过调查发现,WebView 早期是有 bug 的,使用 JS 代码可以通过反射等方式获取到内存卡上的文件,后来修复了这一问题,同时也添加上了一些规则。 1. 设置 WebView 允许执行 JavaScript 代码,`settings.setJavaScriptEnabled(true);` 。 2. JS 调用 Java 时,被调用的方法必须用 `@JavascriptInterface` 标注。 但是设置了之后还是不行,经过查询后发现 WebView 默认是不保存 DOM 的,所以当我注入的 JS 代码遍历时就会出问题,还需要添加一项设置。 3. 设置 `settings.setDomStorageEnabled(true);` 。 最终经过重重磨难,终于比较完美的实现了我想要的效果。 如果想要了解我的话,可以关注我的微博和网站,详情见下方。 微博: http://weibo.com/GcsSloop 网站: http://www.gcssloop.com