Android vector 标签 pathData 详解
转载地址:http://www.jianshu.com/p/a3cb1e23c2c4#rd
Android Support Library 23.2 出来以后,在Android 5.0(API级别21)以前的系统中,也可以定义矢量drawables,即VectorDrawable。它可以在不失清晰度的情况下进行缩放。你仅仅需要需要一个矢量图片的资源文件,而不再需要为每个屏幕密度设置一个资源文件,在一定程度上可以减小项目的体积。
vector 标签下的最主要就是 pathData,其实pathData跟Android中 Path api对路径的定义规则是差不多的,当你掌握了 pathData 的语法,同时有一颗不轻易放弃的心,就可以通过一些简洁的指令完成几乎所有的图案。
越是复杂的东西往往越有规律可循。下面就来详细说说pathData 的语法。给我五!

<!--上面的手掌对应的代码实现-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="
M22,23 q0,4 -4,4 h-7 q-2,0 -3,-1 T1,16 q-0.6,-0.8 0,-2 t5,3
q1,1 2,0 T8,4 q0,-1 0.9,-1.1 t1.1,1 1.5,9 q0.25,0.5 0.5,0.5
t0.5,-0.5 0,-11 q0.2,-1 1.1,-1.1 t1.1,1.1 1,11 q0.25,0.5 0.5,0.5
t0.5,-0.5 0.5,-9 q0.2,-1 1,-1 t1,1 0.5,9 q0.25,0.5 0.5,0.5
t0.5,-0.5 1.2,-6.5 q0.3,-1 1,-1 t0.8,1 -0.8,6 T22,23"/>
</vector>
基本规则
pathData 的指令基本都是由字母跟若干数字组成,数字之间可以用空格或者逗号隔开 (其实逗号会被忽略掉,加上逗号只是一些习惯的问题)。一般来说指令字母分为大小写两种,大写的字母是基于原点的坐标系(偏移量),即绝对位置;小写字母是基于当前点坐标系(偏移量),即相对位置。
移动
- M x,y (m dx, dy) 移动虚拟画笔到对应的点,但是并不绘制。一开始的时候默认是在(0,0)。
直线
- L x,y (l dx, dy) 从当前点划一条直线到对应的点。
- H x (h dx) 从当前点绘制水平线,相当于l x,0
- V y (v dy) 从当前点绘制垂直线,相当于l 0,y
<!--下面的例子除了 pathData, 其他跟此文件一样-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#0000"
android:strokeColor="#000"
android:strokeWidth="0.2"
android:pathData=" M10,10 L10,15 L15,15 L10,10"/>
</vector>

将上述代码 android:pathData=" M10,10 L10,15 L15,15 L10,10"
替换成以下代码效果相同
android:pathData="M10,10 l 0,5 l 5,0 l-5,-5"
android:pathData="M10,10 V 15 H 15 L10,10"
android:pathData="M10,10 v 5 h 5 l-5,-5"
闭合
- Z(或z) 从结束点绘制一条直线到开始点,闭合路径
上面的图形型也可以由以下代码绘制android:pathData="M10,10 v 5 h 5 z"
弧线
- A rx,ry x-axis-rotation large-arc-flag,sweepflag x,y
- a rx,ry x-axis-rotation large-arc-flag,sweepflag dx,dy
rx ry 椭圆半径
x-axis-rotation x轴旋转角度
large-arc-flag 为0时表示取小弧度,1时取大弧度(要长的还是短的)
sweep-flag 0取逆时针方向,1取顺时针方向
x,y (dx,dy) 终点的位置
这个弧线的指令比起直线就相对复杂得多了,7个参数容易搞混了。来看个例子android:pathData="M8,10 a4,6 0 1,1 6 6"

红色(8,10) 是起点, X轴旋转的角度为0,取大弧,顺时针,蓝色(14,16) 是终点。
- 只将x-axis-rotation 改为30跟-30分别对应下面左边跟右边的效果,可见正数是按顺时针旋转负数按逆时针旋转。
x-axis-rotation为30(左)、-30(右)
- 只将large-arc-flag 改为 0
android:pathData="M8,10 a4,6 0 0,1 6 6"
对应下图效果

- 只将sweep-flag改为 0
android:pathData="M8,10 a4,6 0 1,0 6 6"
对应下图效果

网上看到一张图,基本总结了弧线

二阶贝塞尔曲线
- Q x1,y1 x,y ( q dx1,dy1 dx,dy)
- T x,y ( t dx, dy)
先来看看二阶贝赛尔曲线的公式
没想到高数(高中数学)考过149分的我也研究不透这个鬼,还是看看动画吧

一下子感觉清晰了不少,对于Q指令来说(x1,y1)就是P1这个控制点,(x,y)就是终点P2。P0当然就是执行指令前最后的位置。这里有一点需要说明的, q dx1,dy1 dx,dy 这个指令,两个控制点都是相对P0点的。
而T指令又是什么鬼?为什么只有两个参数?其实T指令是在你画完一条贝塞尔曲线后,只需用T指令指定终点,就能画出一条平滑的贝塞尔曲线。控制点被默认为上一次的控制点关于上次终点的中心对称点。比如上次的控制点P1是(6,6),终点P2是(8,10),
那么使用T指令后默认控制点P1`为(10,14)。
举个例子:
android:pathData="M4,10 Q6,6 8,10 Q10,14 12,10"
android:pathData="M4,10 Q6,6 8,10 T12,10"
android:pathData="M4,10 q2,-4 4,0 q2,4 4,0"
android:pathData="M4,10 q2,-4 4,0 t4,0"
这四个对应的都是下面的曲线

三阶贝塞尔曲线
- C x1,y1 x2,y2 x,y ( c dx1,dy1 dx2,dy2 dx,dy)
- S x1,y1 x,y ( s dx1,dy1 dx, dy)
同样,先列下公式
这玩意估计也看不懂,还是结合动画来吧
跟二阶类似,但是三阶有两个控制点,分别是P1(x1,y1),P2(x2,y2)还有终点P3(x,y)。类似的, c dx1,dy1 dx2,dy2 dx,dy 所有的点都是相对于P0,即上一次的终点。
S指令跟T指令类似。S指令相对于C指令少了一个控制点,这个控制点就是上一次最后一个控制点相对上次的终点的中心对称点。还是同样举个例子:
android:pathData="M4,10 C6,6 8,14 10,10 C12,6 14,14 16,10"
android:pathData="M4,10 C6,6 8,14 10,10 S14,14 16,10"
android:pathData="M4,10 c2,-4 4,4 6,0 c2,-4 4,4 6,0"
android:pathData="M4,10 c2,-4 4,4 6,0 s4,4 6,0"
以上四个均会出现下图的效果

实践
终于把所有的指令搞清楚啦,那么接下来就来画一个比较简单的图案吧(为了一次性涉及几乎所有的指令,大家就别在意图画的很丑啦)

首先分析一下这个图的构成。它是一个圆角正方形同时里面有一个镂空的心型。先来看看正方形
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:fillColor="#f24e4e"
android:pathData="M8,4
h24 q4,0 4,4 v24 q0,4 -4,4
h-24 q-4,0 -4,-4 v-24 q0,-4 4,-4"/>
</vector>

细心的同学应该注意到这里没有设置strokeColor,strokeWidth,并且fillColor也不再设置透明了,所以出现的是没有边框的填充效果。上面viewportWidth为40,则把这张图分成40个单位。
在pathData中,首先移动到A(8,4),然后水平移动了24个单位到B(32,4)。接着就是一条二阶贝塞尔曲线,起点是B,控制点是C(36,4),终点是D(36,8)。然后再画一条垂直线到(36,32)…下面的操作都是差不多,就不多说的。这里注意一点,画这个正方形是从A-B-C-D,也就是顺时针的方向,这点对接下来画心型很重要。
画完了圆角正方形,接下来就要画一个镂空的心型。有同学说再加上一个path标签,设置不同颜色就可以。这方法乍一看挺不错,但是他实现的并不是镂空的效果,而是叠加的效果。镂空的话中间的心型是透明的,但是叠加就没办法让中间的心呈透明。
那怎么实现镂空的效果呢?其实关键就是前面说的方向。前面的正方形是顺时针的方向,如果我们在pathData 后面加上另一逆时针方向的路径,就会出现取反的效果,比如
<path
android:fillColor="#f24e4e"
android:pathData="M8,4
h24 q4,0 4,4 v24 q0,4 -4,4
h-24 q-4,0 -4,-4 v-24 q0,-4 4,-4
M2,20 h20 v-10 z"/>
在刚才的基础上加上M2,20 h20 v-10 z
,这是一个逆时针方向的三角形,会变成下面这样

也就是说,我们只需要画一个逆时针方向的心型,就会出现上面的那个效果。先看看代码
<path
android:fillColor="#f24e4e"
android:pathData="M8,4
h24 q4,0 4,4 v24 q0,4 -4,4
h-24 q-4,0 -4,-4 v-24 q0,-4 4,-4
M20,15
a5,6 -15 0 0 -9,2
c0,5 4,6 9,12
c5,-6 9,-7 9,-12
a5,6 15 0 0 -9 -2"/>
这个是在正方形的基础上加上
M20,15
a5,6 -15 0 0 -9,2
c0,5 4,6 9,12
c5,-6 9,-7 9,-12
a5,6 15 0 0 -9 -2
我们看看如果pathData 单独设为上述路径会是什么样的

果然很漂亮。首先它从白色的点
(20,15)开始,向逆时针方向,也就是右边画了一段圆弧到蓝色的点(11,17),圆弧所在的椭圆逆时针转15°,取短弧,逆时针。然后再画一条三阶贝塞尔曲线,控制点分别是黄点(11,22),黑点(15,23),终点是绿色的点(20,
29)。这样子就完成了心型的一半了。另一半跟这边的完全对称,也就不细说了。
完整代码
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="40"
android:viewportHeight="40">
<path
android:fillColor="#f24e4e"
android:pathData="M8,4
h24 q4,0 4,4 v24 q0,4 -4,4
h-24 q-4,0 -4,-4 v-24 q0,-4 4,-4
M20,15
a5,6 -15 0 0 -9,2
c0,5 4,6 9,12
c5,-6 9,-7 9,-12
a5,6 15 0 0 -9 -2"/>
</vector>
一些废话
网上很多介绍VectorDrawable,但是介绍pathData的真的有点少。我也是通过查阅大量的资料,加上实践,基本算对pathData语法入门了吧,这东西掌握了真的不难,还可以装逼哈哈。这篇博客写的时间真的有点长,整整一天,第一写很多不懂的,希望大家多多指教。有机会再写一下Animated Vector Drawables。
原文链接:http://www.jianshu.com/p/a3cb1e23c2c4#rd
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
Android vector 标签 pathData 详解的更多相关文章
- Android vector标签 PathData 画图超详解
SVG是一种矢量图格式,是Scalable Vector Graphics三个单词的首字母缩写.在xml文件中的标签是<vector>,画出的图形可以像一般的图片资源使用,例子如下: &l ...
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
- Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
- 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING
<Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th 2014 Email:skyseraph00@163.com 更多精彩请直接 ...
- Android中Service(服务)详解
http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...
- [转]ANDROID L——Material Design详解(动画篇)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 转自:http://blog.csdn.net/a396901990/article/de ...
- Android屏幕适配问题详解
上篇-Android本地化资源目录详解 :http://www.cnblogs.com/steffen/p/3833048.html 单位: px(像素):屏幕上的点. in(英寸):长度单位. mm ...
- Android开发–Intent-filter属性详解
Android开发–Intent-filter属性详解 2011年05月09日 ⁄ Andriod ⁄ 暂无评论 ⁄ 被围观 1,396 views+ 如果一个 Intent 请求在一片数据上执行一个 ...
- Android目录结构(详解)
Android目录结构(详解) 下面是HelloAndroid项目在eclipse中的目录层次结构: 由上图可以看出项目的根目录下共有九个文件(夹),下面就这九个文件(夹)进行详解: 1.1src文件 ...
随机推荐
- luogu3168 [CQOI2015]任务查询系统
树状数组不用动脑子真爽啊 #include <algorithm> #include <iostream> #include <cstdio> using name ...
- Ext.js双击事件
/** * 联系人列表panel */ Ext.define('Op.OpBill.OpBillCustLinkGridPanel', { extend: 'Ext.grid.Panel', id: ...
- python002 Python3 基础语法
python002 Python3 基础语法 编码默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串. 当然你也可以为源码文件指定不同的编码: # -* ...
- 1013. Battle Over Cities (25)(DFS遍历)
For example, if we have 3 cities and 2 highways connecting city1-city2 and city1-city3. Then if city ...
- 汕头市赛srm10 T2
n个数,分组,数Ai要在至少含有Ai个数的组,求最多分多少组. 方法一:大的数应该尽量跟大的在一起,这样才能让小的出现很多很多组,所以从大到小排序,给当前序列中最大的数x分x个数.代码如下: #inc ...
- Flex4分模块下样式动态加载步骤及相关问题的解决
1. 给应用程序编写CSS文件 (1)在项目下创建CSS文件(任意路径,可以多个).本例在src下创建了5个样式文件 (2)Flex支持的CSS文件定义如下: a) type selector(类 ...
- winServer-常用winrm命令
学习WinServer必须学习powershell,学习powershell必须掌握远程管理服务器的方法,所以必须学会winrm来远程管理服务器 记录一些常用的winrm命令和错误 常用命令 //在P ...
- Codeforces Round #291 (Div. 2) B. Han Solo and Lazer Gun
因为是x,y均为整数因此对于同一直线的点,其最简分数x/y是相同的(y可以为0,这里不做除法)于是将这些点不断求最简分数用pair在set中去重即可. #include <cmath> # ...
- CORS:Source.priciple implimentation in Spring
Cors(Cross-origin Resource Sharing)一种跨域访问技术,基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定响应成功与否. CORS与JSONP对 ...
- mysql写入数据乱码问题的解决
mysql默认编码为latin. 我的mysql版本为5.6.安装路径下没有my.ini,但是有my-default.ini.其实mysql没有配置文件也是可以启动的,但是为了设置编码,需要将my-d ...