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文件 ...
随机推荐
- 【02】sass更新的方法
[02]更新的方法 gem install sass **
- STM32F407 STLINK 在线调试 个人笔记
配置的部分请看本博客STM32分类下的环境配置篇目 开始调试 一些按键 查看寄存器 查看变量值 选中变量,右键,add to watch
- 【Ajax 1】Ajax与传统Web开发的区别
导读:从用户体验度的角度来说,利用Ajax进行开发的网站,其体验度高于利用传统Web开发技术,那么,是什么因素导致了这一现象呢?难道说Ajax开发,就一定优于传统Web技术吗?本篇文章,将主要介绍Aj ...
- python 快排,堆排,归并
#归并排序 def mergeSort(a,L,R) : if(L>=R) : return mid=((L+R)>>1) mergeSort ...
- 【贪心】HDU 最少拦截系统
https://vjudge.net/contest/68966#problem/I [题解] http://www.cnblogs.com/kuangbin/archive/2012/08/03/2 ...
- hdu 1689 求奇环bfs关键是层次图
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> usin ...
- app后端搜索入门
现在人们的网络生活已经离不开搜索了,遇到不懂的问题,想知道的事情,搜索一下,就知道答案. 在app中,最常见的搜索情景就是搜索用户.只有几百,几千的用户量时,可以直接用用like这样的模糊查询,但是, ...
- CSY版最大团,速度快一倍
#include <bits/stdc++.h> using namespace std; #define REP(i, n) for(int i(0); i < (n); ++i) ...
- 最长不下降子序列 (O(nlogn)算法)
分析: 定义状态dp[i]表示长度为i的最长不下降子序列最大的那个数. 每次进来一个数直接找到dp数组第一个大于于它的数dp[x],并把dp[x - 1]修改成 那个数.就可以了 AC代码: # in ...
- Spring Boot+Profile实现不同环境读取不同配置
文件结构如下: 但是官方推荐放在config文件夹下. 作用: 不同环境的配置设置一个配置文件,例如:dev环境下的配置配置在application-dev.properties中.prod环境下的配 ...