Webview优化 | 优雅的在手机上阅读代码

手机阅读代码之痛

在手机上阅读代码体验肯定不会在电脑上方便,尤其是一些冗长的代码,可能会有几行代码显得很长,又没有做换行处理。正常来说,一般人的阅读应该是从左到右读完一行,然后从上至下读下一行。虽然经过pre codehtml标签处理的代码可以左右滑动代码阅读,但是对于一些记性不太好的朋友通常在滑动读完第一行,继续左右滑动阅读第二三行时,可能就忘了第一行,又得滑动看看第一行。比如如下代码:

这是一段很长的代码~~~~~!!!~~~代码中间~~~~~~~~~~~~~~~~~啦啦啦第一行结尾
System.out.println("Hello World..............+++++++............................end")
第二行代码--------------------------------中间~~~~~~~第二行结尾1=1
//~~~~~~~~~~~~~

总的来说,代码读起来不流程,完整性不好。因为手机屏幕的原因,导致我们必须得滑动读。当然我们也可以进行通过换行处理代码提升体验,可我们不能保证所有的文章都做了这么处理,而且有些代码做换行处理也不会很理想。

优雅阅读代码

那么应该怎样提升阅读代码的体验呢?在微信阅读app中,它将代码裁剪成几个片段,点击时又可以显示完整对代码图片。事实上,在现在这种大屏手机时代,一张完整代码图片是可以阅读的,读起来更加完整,流畅。
为了在WebView上能更好阅读代码,做了代码图片展示功能,能让我们更优雅的在手机上阅读代码(见下图)。

代码1
代码2

较微信阅读,新增横屏模式,更清楚的阅读代码。

如何实现

首先想到的是要对应precode标签下的dom节点转成图片。在github上,最终找到了dom-to-image,它就是一款能够将任意的dom节点转成图片的js库。

webview加载dom-to-image

直接将dom-to-image.js源码保存至assets目录下。在WebView加载完成网页时(onPageFinished)时,载入dom-to-image的代码。

object FileUtil {
   ...
    fun readStringInAssets(path: String): String {
        val input = App.instance.assets.open(path)
        val len = input.available();
        val buffer = ByteArray(len)
        input.read(buffer)
        return String(buffer, Charset.forName("utf-8"))
    }
}
//在webview onPageFinished调用
val dom2ImageScript = FileUtil.readStringInAssets("dom-to-image.js")
webView.evaluateJavascript(dom2ImageScript) {
       "result:$it".logE()
 }

然后我们就能找到domtoimage这个对象了

image.png

我们通过chrome://inspect/地址,在Console下编写调试代码。我们加入下面的代码:

var pre = document.getElementsByTagName("pre");
domtoimage.toPng(pre)
  .then(function(data){
      console.log(data);
  });

image.png

我们将上面的base64形式的图片数据拷贝复制到浏览器上,得到了以下图片
image.png

可以发现图片并不是完整的。我们需要将宽度增大到实际可滚动的宽度。我们在toPng方法中加入width属性,不同站点对于代码的处理方式是不一样的,有点是在pre内滚动,有的则是在code内部滚动。玩Android站点是在code内部滚动的,所以基于code保存图片

var code = pre.children[0];
domtoimage.toPng(code,{width:code.scrollWidth})
          .then(function(data){
                console.log(data);
           });

最终图片如下:


image.png

图片模糊?

最终生成的代码图片我们发现代码有些模糊的,图片大小像素并不匹配手机的分辨率。因为WebView中的px并不匹配手机实际的像素。所以我们要针对手机实际的像素大小进行放大。在css中我们可以通过transform:scale(1.5)之类的代码将dom节点缩放,同时dom-to-image是支持自定义style的。因此可以实现代码图片真正像素显示。
在次之前,要先得到放大比例,然后给每个pre添加点击事件:

val ww = webView.width
val script = """
 var ww = ${ww}.0;
 var scale = ww/outerWidth;
 //以下为JavaScript代码见下一个
 //pre点击事件代码
  """.trimIndent()
webView.evaluateJavascript(script){
  "result:$it".logE();
}

下面是对pre要添加点击事件的代码,不同站点对于代码展示处理做了兼容。

 //pre点击事件代码
var pres = document.getElementsByTagName("pre");
  for(var i=0;i<pres.length;i++){
    pres[i].onclick = function(e){
        var imgWidth = this.scrollWidth;
        var node = this;
        for(var n=0;n<this.childElementCount;n++){
            var child = this.children[n];
            if(child.tagName=="CODE"){
            var cw = child.scrollWidth;
                if(cw>imgWidth){
                    imgWidth = cw;
                    node = child;
                }
            }
        }
        
        imgWidth = imgWidth+3;
        var imgHeight = node.offsetHeight;
        var rect = node.getBoundingClientRect();
        console.log(node.tagName);
        domtoimage.toPng(node,{width:imgWidth*scale,height:imageHeight*scale,
                style: {
                    transform: "scale(" + scale + ")",
                    transformOrigin: "top left",
                    width: imgWidth + "px",
                    height: rect.height + "px"
                }
            })
            .then(function(data){
                console.log(data);
                android.showImage(data,rect.x,rect.y,imgWidth,rect.height,outerWidth);
            });
    };
}

最终通过android.showImage回调给Android端显示图片,具体图片展示可以见前一篇Glide实现WebView离线图片的酷炫展示效果。因为Glide是支持Base64字符串图片展示的,因此能之前写的图片展示也不用怎么改。不过要注意的是Intent传递数据是有大小限制的,而我们的Base64字符串可能会很大,需要避免用Intent传递数据,一种方法是用共享变量传递。

val activity = iv.getActivity()
            activity?.let {
                val pair: Pair<View, String> = Pair(iv, "image")
                val option =
                    ActivityOptionsCompat.makeSceneTransitionAnimation(
                        it,
                        pair
                    )
                val intent = Intent(it, ImageShowActivity::class.java)
                Constants.sharedUrl = url
                it.startActivityForResult(intent, 1, option.toBundle())
            }

项目地址

https://github.com/iamyours/Wandroid
最新apk地址
版本历史

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355