今天开始说一下矢量图和矢量动画。
1.矢量图的定义
矢量是一种既有大小又有方向的几何对象,它通常被标示为一个带箭头的线段。若干个矢量拼接在一起,便形成了矢量图形。矢量图不同于一般的图形,它是由一系列几何曲线构成的图像,这些曲线又以数学上定义的坐标点连接而成。
2.矢量图使用的开启方法
在文件内部的defaultConfig节点之下添加下面一行配置,表示开启矢量图形的支持库
vectorDrawables.useSupportLibrary = true
3.矢量图不失真原因
因为绘图结果是动态计算得到,所以不管缩放到多少比例,矢量图形都会一样的清晰,不像普通位图那样拉大后会变模糊。
4.矢量图形XML的结构和主要属性
矢量图形的XML文件结构可分为三个层次:根标签,组标签,路径标签。下面是各个标签对应的相关属性
<1>根标签vector
vector标签表示当前定义的是一个完整的矢量图形。该标签支持的主要属性说明如下。
- android:name:指定矢量图形的名称
- android:width:指定矢量图形的默认宽度,一般使用dp数值。如果在layout布局文件中将ImageView的layout_width设置为wrap_content,同时src设置为该矢量图形,则ImageView控件的宽度就是此处的android:width。
- android:height:指定矢量图形的默认高度,一般使用dp数值。
- android:viewportWidth:指定视图空间的宽度,即虚拟坐标系的宽度,后续路径的坐标信息都位于该视图空间内。
- android:viewportHeight:指定视图空间的高度,即虚拟坐标系的高度。
- android:alpha:指定矢量图形的透明度,取值为0.0到1.0
这里要注意width/height与viewportWidth/viewportHeight两组宽高的区别,前者指的是矢量图形被外部世界观察到的尺寸大小,故而采用了带dp单位的绝对数值;而后者指的是矢量图形为内部几何路径所参照的空间范围,故而采用了不带单位的相对数值。正因为矢量图形中的几何路径以相对坐标来标记,所以不管矢量图形缩放到多少比例,其内部的几何形状也会按同样比例缩放。
<2>组标签group
group标签定义了一组路径的共同行为(如一起旋转、一起缩放、一起平移等)。该标签支持的主要属性说明如下。
- android:name:指定分组对象的名称。
- android:pivotX:指定旋转中心点的横轴坐标。
- android:pivotY:指定旋转中心点的纵轴坐标。
- android:rotation:指定分组对象的旋转角度。
- android:scaleX:指定分组对象在横轴上的缩放比例。取值0.5表示缩小一半,取值2.0表示放大一倍。
- android:scaleY:指定分组对象在纵轴上的缩放比例。
- android:translateX:指定分组对象在横轴上的平移距离。
- android:translateY:指定分组对象在纵轴上的平移距离。
<3>路径标签path
path标签定义了一个路径的几何描述,既可以表示一根曲线,也可以表示一块平面区域,该标签支持的主要属性说明如下。
- android:name:指定几何路径的名称。
- android:pathData:指定几何路径的数据定义。数据格式需符合SVG标准。
- android:fillColor:指定平面区域的颜色。若不指定,则不绘制平面区域。
- android:fillAlpha:指定平面区域的透明度。
- android:strokeColor:指定曲线的颜色。若不指定,则不绘制曲线颜色。
- android:strokeWidth:指定曲线的宽度。
- android:strokeAlpha:指定曲线的透明度。
- android:strokeLineCap:指定曲线的首尾外观。取值说明有三个:butt(默认值,直线边缘)、round(圆形边缘)、square(方形边缘)。
- android:strokeLineJoin:指定两条曲线相交的边角外观。取值说明有三个:miter(默认值,锐角)、round(圆角)、bevel(钝角)。
- android:trimPathStart:指定几何路径从哪里开始绘制。取值为0.0到1.0,比如取值0.4表示只绘制后面十分之六的内容,前面十分之四不予绘制。
- android:trimPathEnd:指定几何路径到哪里结束绘制。取值为0.0到1.0,比如取值0.4表示只绘制前面十分之四的内容,后面十分之六不予绘制。
- android:trimPathOffset:指定几何路径的绘制偏移。取值为0.0到1.0,表示线条从trimPathOffset+trimPathStart处一直绘制到trimPathOffset+trimPathEnd处。
路径信息有几个地方容易混淆,下面补充说明一下相关细节:
- 关于直线边缘buff和方形边缘square的区别,咋看起来直线边缘与方形边缘没什么差别,但矢量图形的方形边缘其实是套上一个方形的帽子,既然是套上去,就会比没戴帽子的时候高一点,所以使用square的线条会比使用buff的线条要长一点。
- 关于锐角miter和钝角bevel的区别,miter保留了原样的尖角,而bevel会把尖角部分切掉一小块,看起来就变钝了。
- trimPathOffset+trimPathEnd相加的和如果超过1,也会部分画出来,绘制的是从起点到(trimPathOffset+trimPathEnd-1)所处的位置
本文的意义:
有些同学看完会说,这啥也没讲啊,我依然无法得到一个能用的矢量图形。别急,其实矢量图形很多时候都不是我们自己画的,都是UI给我们的SVG图。有了这些属性含义的知识储备,我们就可以很轻松地对现有的矢量图形进行修改,实现我们使用SVG的目标。后面我还会详细记录SVG的相关使用。
5.使用示例
vetor.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportHeight="1024"
android:viewportWidth="1024">
<path
android:fillColor="#F85F69"
android:pathData="M782.5408 934.3488H248.7296c-73.5232 0-133.12-59.5968-133.12-133.12V218.4192c0-73.5232 59.5968-133.12 133.12-133.12h533.8112c73.5232 0 133.12 59.5968 133.12 133.12v582.8096c0 73.5232-59.5968 133.12-133.12 133.12z" />
<path
android:fillColor="#F33B3D"
android:pathData="M915.5072 212.6336c-3.0208-70.8608-61.3888-127.3344-132.9664-127.3344H248.7296c-71.5776 0-129.9456 56.5248-132.9664 127.3344 3.1232 218.2656 180.8896 394.24 399.872 394.24 218.9824 0 396.7488-175.9744 399.872-394.24z" />
<path
android:fillColor="#F7F8F8"
android:pathData="M515.6352 510.1056c-77.4656 0-140.4928-63.0272-140.4928-140.4928s63.0272-140.4928 140.4928-140.4928 140.4928 63.0272 140.4928 140.4928-63.0272 140.4928-140.4928 140.4928z m0-199.0144c-32.3072 0-58.5728 26.2656-58.5728 58.5728s26.2656 58.5728 58.5728 58.5728 58.5728-26.2656 58.5728-58.5728-26.3168-58.5728-58.5728-58.5728z" />
</vector>
这就是我们的矢量图形,先说说这个是从哪里来的,首先我要找个图标,这个可能是你们UI给你的,也可能是你从矢量图标库下载的,比如我从阿里巴巴矢量图下了一个红包的图标,如下
下载下来的源码如下
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1626746997230"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="23231"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="200"
height="200">
<defs>
<style type="text/css"></style>
</defs>
<path
d="M782.5408 934.3488H248.7296c-73.5232 0-133.12-59.5968-133.12-133.12V218.4192c0-73.5232 59.5968-133.12 133.12-133.12h533.8112c73.5232 0 133.12 59.5968 133.12 133.12v582.8096c0 73.5232-59.5968 133.12-133.12 133.12z"
fill="#F85F69"
p-id="23232"></path>
<path
d="M915.5072 212.6336c-3.0208-70.8608-61.3888-127.3344-132.9664-127.3344H248.7296c-71.5776 0-129.9456 56.5248-132.9664 127.3344 3.1232 218.2656 180.8896 394.24 399.872 394.24 218.9824 0 396.7488-175.9744 399.872-394.24z"
fill="#F33B3D"
p-id="23233"></path>
<path
d="M515.6352 510.1056c-77.4656 0-140.4928-63.0272-140.4928-140.4928s63.0272-140.4928 140.4928-140.4928 140.4928 63.0272 140.4928 140.4928-63.0272 140.4928-140.4928 140.4928z m0-199.0144c-32.3072 0-58.5728 26.2656-58.5728 58.5728s26.2656 58.5728 58.5728 58.5728 58.5728-26.2656 58.5728-58.5728-26.3168-58.5728-58.5728-58.5728z"
fill="#F7F8F8"
p-id="23234"></path>
</svg>
其中
这个是我们viewPort两个属性的数值,
这个是我们的图形默认宽高
这三个path就是我们的path了,所以最后修改好就是我们之前贴出来的代码
然后我们只要代码中为我们的ImageView设置即可
iv_vector.setImageResource(R.drawable.vector_heart);