Android:将自定义View的手签信息保存为SVG文件

我正在参加「掘金·启航计划」,这是我参加的第3篇文章。

上文自定义View实现签名带笔锋效果中我们实现了带笔锋的手签字功能。正常需求只需将其视图信息转换为Bitmap,然后保存为图片即可。或者要求稍微高一点的会将这个Bitmap周围多余的白边给去掉,只截取文字区域。但这次,我接到的需求是保存为SVG文件。

众所周知,安卓中的SVG和前端那边的SVG区别还是比较大的。因为此次的手签信息需要传给前端使用,所以我们得熟悉下以前没怎么接触过的SVG标签了。

网上搜了一些资料后发现其实挺简单。都是一些标签,和我们写xml类似,我们要做的就只是照葫芦画瓢。

分析:

我们的签名信息最终是用N个椭圆绘制完成,那么在SVG中也可使用椭圆标签 ellipse 来完成绘制。其中包含了 cx、cy、rx、ry参数,不难看出这四个参数就是椭圆的圆心坐标点和x、y方向上的直径。这些信息在我们保存的点信息中都可通过计算得到。关于SVG的宽高在svg标签中可以直接赋值。

示例如下:

StringBuilder sb = new StringBuilder();
//svg宽高信息
sb.append("<svg  width= x  height= y  xmlns="http://www.w3.org/2000/svg" version="1.1">");

for (int i = 0; i < svgLineAllList.size(); i++) {
    ArrayList<SvgPointBean> list = svgLineAllList.get(i);
    if (list.size() <= 0) {
        continue;
    }
    String color = TransUtils.colorToHex(list.get(0).getColor());
    sb.append("<g fill= color >");
    for (int j = 0; j < list.size(); j++) {
        SvgPointBean b = list.get(j);
        //绘制椭圆  cx、cy为中心点 rx、ry为x、y直径
        sb.append(
        "<ellipse 
        cx=(b.getRectF().left + b.getRectF().right) / 2 
        cy=(b.getRectF().bottom + b.getRectF().top) / 2 
        rx=b.getRectF().right - b.getRectF().left 
        ry=b.getRectF().bottom - b.getRectF().top
        />");
    }
    sb.append("</g>");
}

sb.append("</svg>");

其实到这已经实现了SVG文件的生成,获取该SVG文件解析时则需要安卓自带的 DocumentBuilderFactory 库解析,在这里就不多做介绍。

优化:

  1. 眼尖的同学可能已经发现上面的SVG文件中有一个g标签,它的作用非常妙!既能作为线条的区分,还能统一该线条下所有椭圆的颜色。隐形之中还缩小了SVG文件的大小。
  2. 由于触摸事件得到的点坐标都是浮点类型,有的点甚至达到了四五位小数点。当我们收集的点越多,那么SVG的长度就会更大。所以我们可以在收集点的时候丢失精度,保留一位小数即可(根据实际效果保留小数点)。
  3. SVG的局部显示。当一个屏幕我只写了一个字,此时我只想保留有效区域。这时不得不介绍下viewBox属性,它就能帮我们实现这个效果。通过遍历所有点,找到签名点的最左、最右、最上、最下四个点得出SVG文件的宽高,最后将值赋值给viewBox。
  4. SVG文件的缩放,其实就是通过对所有点的放大和缩小。这里有个问题就是缩放因子这个参数要放在哪里?通过测试发现,在svg标签里可以自己添加自定义标签,生成的时候将缩放因子设置好,解析的时候通过该标签拿到缩放因子再恢复坐标点即可。

好了,以上便是手签名信息保存为SVG文件的一些经验,希望对大家有所帮助。  

我是一个喜爱Jay、Vae的安卓开发者,喜欢结交五湖四海的兄弟姐妹,欢迎大家到沸点来点歌!