当前位置: 首页 > news >正文

Android UI进阶之旅15 SVG的使用

###多媒体图片的基本概念

  1. 矢量图像(消耗CPU,不占内存):SVG是W3C 推出的一种开放标准的文本式矢量图形描述语言,他是基于XML的、专门为网络而设计的图像格式,SVG是一种采用XML来描述二维图形的语言,所以它可以直接打开xml文件来修改和编辑。
  2. 位图图像(不消耗CPU,占内存):位图图像(BitMap)的存储单位是图像上每一点的像素值,因而文件会比较大,像GIF、JPEG、PNG等都是位图图像格式。

###SVG

SVG,即Scalable Vector Graphics 可伸缩矢量图形,这种图像格式在前端中已经使用的非常广泛了。

######SVG的W3C的解释: http://www.w3school.com.cn/svg/svg_intro.asp

###Android中使用SVG

Android中通过Vector使用SVG,在Android中指的是Vector Drawable,也就是Android中的矢量图,SVG的阉割版。可以说Vector就是Android中的SVG实现(并不是支持全部的SVG语法,现已支持的完全足够用了)

补充:Vector图像刚发布的时候,是只支持Android 5.0+的,自从AppCompat 23.2之后,Vector可以使用于Android 2.1以上的所有系统,只需要引用com.android.support:appcompat-v7:23.2.0以上的版本就可以了。(所谓的兼容也是个坑爹的兼容,即低版本非真实使用SVG,而是生成PNG图片(AS编译打包的时候自动生成))

###Vector Drawable基本简介

Android 5.0发布的时候,Google提供了Vector的支持,即:Vector Drawable类。

####优势

Vector Drawable相对于普通的Drawable来说,有以下几个好处:

  1. Vector图像可以自动进行适配,不需要通过分辨率来设置不同的图片。
  2. Vector图像可以大幅减少图像的体积,同样一张图,用Vector来实现,可能只有PNG的几十分之一。
  3. 使用简单,很多设计工具,都可以直接导出SVG图像,从而转换成Vector图像 功能强大。
  4. 不用写很多代码就可以实现非常复杂的动画 成熟、稳定,前端已经非常广泛的进行使用了。

####基本语法

通过使用它的Path标签,几乎可以实现SVG中的其它所有标签,虽然可能会复杂一点,但这些东西都是可以通过工具来完成的,所以,不用担心写起来会很复杂。

Path指令解析如下所示:

M = moveto(M X,Y) :将画笔移动到指定的坐标位置,相当于 android Path 里的moveTo()
L = lineto(L X,Y) :画直线到指定的坐标位置,相当于 android Path 里的lineTo()
H = horizontal lineto(H X):画水平线到指定的X坐标位置 
V = vertical lineto(V Y):画垂直线到指定的Y坐标位置 
C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三次贝赛曲线 
S = smooth curveto(S X2,Y2,ENDX,ENDY) 同样三次贝塞尔曲线,更平滑 
Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二次贝赛曲线 
T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射 同样二次贝塞尔曲线,更平滑 
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线 ,相当于arcTo()
Z = closepath():关闭路径(会自动绘制链接起点和终点)

注意,’M’处理时,只是移动了画笔, 没有画任何东西。
复制代码

####Tips

  1. 关于这些语法,开发者不需要全部精通,而是能够看懂即可,这些path标签及数据生成都可以交给工具来实现。 (一般美工来帮你搞定!PS、Illustrator等等都支持导出SVG图片)
  2. 程序员:没必要去学习使用这些设计工具,开发者可以利用一些工具,自己转换一些比较基础的图像, 如:http://inloop.github.io/svg2android/
  3. 还可以使用SVG的编辑器来进行SVG图像的编写,例如:http://editor.method.ac/ (绝配!可以先用http://editor.method.ac/ 生成SVG图片,然后用http://inloop.github.io/svg2android/ 生成 VectorDrawable xml代码)
  4. 使用AndroidStudio插件完成SVG添加(Vector Asset Studio) 详细:http://www.jianshu.com/p/d6c39f2dd5e7 AS会自动生成兼容性图片(高版本会生成xxx.xml的SVG图片;低版本会自动生成xxx.png图片)
  5. 有些网站可以找到SVG资源 SVG下载地址: http://www.shejidaren.com/8000-flat-icons.html http://www.flaticon.com/

####例子--静态Vector

我们可以到http://editor.method.ac/画一张SVG,然后通过http://inloop.github.io/svg2android/转换成Android支持的xml。

这里为了方便,我直接到http://www.flaticon.com/找一张SVG图片,然后通过Android Studio进行转换,具体操作如下:

选中Drawable目录,右击,选择创建Vector Asset:

选择电脑中的SVG图片,确定,这里可以做一些简单的编辑,最后点击完成:

生成的xml如下:

<vector android:height="24dp" android:viewportHeight="115.572"
    android:viewportWidth="115.572" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#E7831E" android:pathData="M70.19,114.09c0,0.82 -0.66,1.48 -1.48,1.48l0,0c-0.82,0 -1.48,-0.66 -1.48,-1.48v-9.22c0,-0.82 0.66,-1.48 1.48,-1.48l0,0c0.82,0 1.48,0.66 1.48,1.48V114.09z"/>
    <path android:fillColor="#E7831E" android:pathData="M76.49,110.03c0.6,0.56 0.64,1.49 0.08,2.1l0,0c-0.56,0.6 -1.49,0.64 -2.1,0.08l-6.78,-6.26c-0.6,-0.56 -0.64,-1.49 -0.08,-2.1l0,0c0.56,-0.6 1.49,-0.64 2.1,-0.08L76.49,110.03z"/>
    <path android:fillColor="#E7831E" android:pathData="M60.93,110.03c-0.6,0.56 -0.64,1.49 -0.08,2.1l0,0c0.56,0.6 1.49,0.64 2.1,0.08l6.78,-6.26c0.6,-0.56 0.64,-1.49 0.08,-2.1l0,0c-0.56,-0.6 -1.49,-0.64 -2.1,-0.08L60.93,110.03z"/>
    <path android:fillColor="#E7831E" android:pathData="M48.56,114.09c0,0.82 -0.66,1.48 -1.48,1.48l0,0c-0.82,0 -1.48,-0.66 -1.48,-1.48v-9.22c0,-0.82 0.66,-1.48 1.48,-1.48l0,0c0.82,0 1.48,0.66 1.48,1.48V114.09z"/>
    <path android:fillColor="#E7831E" android:pathData="M54.86,110.03c0.6,0.56 0.64,1.49 0.08,2.1l0,0c-0.56,0.6 -1.49,0.64 -2.1,0.08l-6.78,-6.26c-0.6,-0.56 -0.64,-1.49 -0.08,-2.1l0,0c0.56,-0.6 1.49,-0.64 2.1,-0.08L54.86,110.03z"/>
    <path android:fillColor="#E7831E" android:pathData="M39.29,110.03c-0.6,0.56 -0.64,1.49 -0.08,2.1l0,0c0.56,0.6 1.49,0.64 2.1,0.08l6.78,-6.26c0.6,-0.56 0.64,-1.49 0.08,-2.1l0,0c-0.56,-0.6 -1.49,-0.64 -2.1,-0.08L39.29,110.03z"/>
    <path android:fillColor="#FDBD2C" android:pathData="M90.38,73.64c0,17.67 -14.33,32 -32,32H57.19c-17.67,0 -32,-14.33 -32,-32v-36.25c0,-17.67 14.33,-32 32,-32h1.19c17.67,0 32,14.33 32,32V73.64z"/>
    <path android:fillColor="#FDBD2C" android:pathData="M57.19,5.39c0,0 14.52,0.06 17.02,-5.39c0,0 1.93,2.22 0,5.39c0,0 0.17,1.16 3.17,0c0,0 1.67,0.61 -4.67,3.39"/>
    <path android:fillColor="#F4C778" android:pathData="M77.64,85.78c0,10.97 -8.89,19.86 -19.86,19.86l0,0c-10.97,0 -19.86,-8.89 -19.86,-19.86v-6.48c0,-10.97 8.89,-19.86 19.86,-19.86l0,0c10.97,0 19.86,8.89 19.86,19.86V85.78z"/>
    <path android:fillColor="#F2B02A" android:pathData="M82.05,61.02l4.08,14.87c0.94,3.41 4.46,5.41 7.87,4.48l0,0c3.41,-0.94 5.41,-4.46 4.48,-7.87c0,0 -0.99,-4.63 -1.66,-6.05C95.15,62.89 92.13,59.76 82.05,61.02z"/>
    <path android:fillColor="#F2B02A" android:pathData="M33.52,61.02l-4.08,14.87c-0.94,3.41 -4.46,5.41 -7.87,4.48l0,0c-3.41,-0.94 -5.41,-4.46 -4.48,-7.87c0,0 0.99,-4.63 1.66,-6.05C20.43,62.89 23.44,59.76 33.52,61.02z"/>
    <path android:fillColor="#1A1A1A" android:pathData="M43.29,40.09m-3.96,0a3.96,3.96 0,1 1,7.93 0a3.96,3.96 0,1 1,-7.93 0"/>
    <path android:fillColor="#FFFFFF" android:pathData="M43.29,39.33c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5c0,0.83 -0.67,1.5 -1.5,1.5C43.96,40.83 43.29,40.15 43.29,39.33z"/>
    <path android:fillColor="#1A1A1A" android:pathData="M72.28,40.09m-3.96,0a3.96,3.96 0,1 1,7.93 0a3.96,3.96 0,1 1,-7.93 0"/>
    <path android:fillColor="#FFFFFF" android:pathData="M72.28,39.33c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5c0,0.83 -0.67,1.5 -1.5,1.5C72.95,40.83 72.28,40.15 72.28,39.33z"/>
    <path android:fillColor="#E7831E" android:pathData="M57.79,57.39l-3.78,-6.55l-3.78,-6.55l7.56,0l7.56,0l-3.78,6.55z"/>
</vector>
复制代码

解释头部的几个标签:

  • android:width \ android:height:定义图片的宽高
  • android:viewportHeight \ android:viewportWidth:定义图像被划分的比例大小,例如例子中的500,即把200dp大小的图像划分成500份,后面Path标签中的坐标,就全部使用的是这里划分后的坐标系统。

这样做有一个非常好的作用,就是将图像大小与图像分离,后面可以随意修改图像大小,而不需要修改PathData中的坐标。

最后,使用图片,就当普通的图片使用就可以了。当然也可以当作selector使用等:

<ImageView
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:src="@drawable/ic_chick"/>
复制代码

这时候你会发现,使用SVG图片之后,无论ImageView放大还是缩小,都没有失真了。但是SVG画出来的一般都是一些比较扁平、简单的图片。

####例子--动态Vector

动态Vector才是Android Vector Drawable的精髓所在,下面以搜索条为例子进行介绍:

首先画一个搜索条(drawable目录):

searchbar.xml:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="150dp"
        android:height="24dp"
        android:viewportHeight="24"
        android:viewportWidth="150">

    <path
        android:name="search"
        android:pathData="M141,17 A9,9 0 1,1 142,16 L149,23"
        android:strokeAlpha="0.8"
        android:strokeColor="#000000"
        android:strokeLineCap="round"
        android:strokeWidth="2"/>
    <path
        android:name="bar"
        android:pathData="M0,23 L149,23"
        android:strokeAlpha="0.8"
        android:strokeColor="#000000"
        android:strokeLineCap="square"
        android:strokeWidth="2"/>
</vector>
复制代码

添加动画(drawable目录):

searchbar_anim.xml:

<animated-vector
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/searchbar">

    <target
        android:name="search"
        android:animation="@animator/anim_searchbar_in"/>

    <target
        android:name="bar"
        android:animation="@animator/anim_searchbar_out"/>

</animated-vector>
复制代码

其中,drawable是指定哪个SVG图片,target是指定动画

anim_searchbar_in、anim_searchbar_out的定义如下(animator目录):

anim_searchbar_in.xml:

<objectAnimator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="trimPathStart"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:valueFrom="0"
    android:valueTo="1"
    android:valueType="floatType"/>
复制代码

anim_searchbar_outxml:

<objectAnimator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="trimPathStart"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:valueFrom="1"
    android:valueTo="0"
    android:valueType="floatType"/>
复制代码

最后,在ImageView中使用:

<ImageView
    android:id="@+id/iv_test"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:srcCompat="@drawable/searchbar_anim"/>
复制代码

######注意:这种Animator只支持5.0+,低于这个版本会崩溃,存在兼容性问题。

####SVG图片的性能问题

  1. Bitmap的绘制效率并不一定会比Vector高,它们有一定的平衡点,当Vector比较简单时,其效率是一定比Bitmap高的,所以,为了保证Vector的高效率,Vector需要更加简单,PathData更加标准、精简,当Vector图像变得非常复杂时,就需要使用Bitmap来代替了
  2. Vector适用于ICON、Button、ImageView的图标等小的ICON,或者是需要的动画效果,由于Bitmap在GPU中有缓存功能,而Vector并没有,所以Vector图像不能做频繁的重绘
  3. Vector图像过于复杂时,不仅仅要注意绘制效率,初始化效率也是需要考虑的重要因素

####参考资料:

微信引入的SVG技术:

http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=207863967&idx=1&sn=3d7b07d528f38e9f812e8df7df1e3322&scene=4#wechat_redirect

如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:

我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)

相关文章:

  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • Android的一些命名规范
  • 零元学Expression Blend 4 - Chapter 13 用实例了解布局容器系列-「Pathlistbox」I
  • Spring源码系列-容器刷新
  • WPF用样式实现TextBox的虚拟提示效果
  • ReactiveCocoa学习
  • [POJ2411]Mondriaan's Dream
  • CentOS7防火墙
  • vue.js 初步学习资源
  • Atlassian发布JIRA项目组合管理解决方案
  • 图片后门恶意捆绑工具FackImageexploer
  • php扩展模块安装
  • Android Studio 3.0 Android 分析器 | 中文教学视频
  • GeoIP2 数据库更新地址
  • 个人常用iOS第三方库以及XCode插件介绍
  • .pyc 想到的一些问题
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • crontab执行失败的多种原因
  • export和import的用法总结
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • KMP算法及优化
  • markdown编辑器简评
  • Objective-C 中关联引用的概念
  • python3 使用 asyncio 代替线程
  • Python语法速览与机器学习开发环境搭建
  • Sass Day-01
  • Spring Cloud中负载均衡器概览
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 开源地图数据可视化库——mapnik
  • 坑!为什么View.startAnimation不起作用?
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 听说你叫Java(二)–Servlet请求
  • Mac 上flink的安装与启动
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • #我与Java虚拟机的故事#连载04:一本让自己没面子的书
  • (二)Linux——Linux常用指令
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .NetCore部署微服务(二)
  • .net分布式压力测试工具(Beetle.DT)
  • /proc/stat文件详解(翻译)
  • [2008][note]腔内级联拉曼发射的,二极管泵浦多频调Q laser——
  • [Dxperience.8.*]报表预览控件PrintControl设置
  • [ISITDTU 2019]EasyPHP
  • [javascript]Tab menu实现
  • [LeetCode] NO. 169 Majority Element
  • [LeetCode] Verify Preorder Sequence in Binary Search Tree 验证二叉搜索树的先序序列
  • [NOIP2018 PJ T4]对称二叉树
  • [Open3d]: 知识记录
  • [OS-Linux] CentOS 7.x 使用密钥登录安全设置