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

作者: 星星y | 来源:发表于2020-07-04 11:49 被阅读0次

    手机阅读代码之痛

    在手机上阅读代码体验肯定不会在电脑上方便,尤其是一些冗长的代码,可能会有几行代码显得很长,又没有做换行处理。正常来说,一般人的阅读应该是从左到右读完一行,然后从上至下读下一行。虽然经过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地址
    版本历史

    相关文章

      网友评论

        本文标题:Webview优化 | 优雅的在手机上阅读代码

        本文链接:https://www.haomeiwen.com/subject/tigyqktx.html