概述
Android 5.0(21)引入矢量图,
● 可缩放向量图形:Scalable Vector Graphics,SVG)是一种基于可扩展标记语言(XML),用于描述二维向量图形的图形格式。SVG由W3C制定,是一个开放标准。
● 优点
○ SVG何以可以任意缩放而不会失真
○ SVG文件一般都比较小,省去很去资源达到apk缩包的目的
○ SVG占用内存非常小,性能高。
● 缺点
○ SVG明显的缺点是没有位图表达的色彩丰富。==>Android7.0(24)可以通过aapt:attr设置渐变色等所需要实现的颜色效果(包含将变色等)
基础语法
注意一下指令都存在大小写的形式,大写表示后面的参数是绝对坐标,小写表示相对于上一个点的相对坐标位置,参数可以用逗号或者空格分离
● Mx,y:起始点即确定绘制的起始点(x:起始点X坐标,y:起始点Y坐标)
● Lx,y:直线连接点(x:连接点的X坐标,y:连接点的Y坐标)
● Z:close关闭绘制
● Arx,ry,x-axis-rotation,large-arc-flag,sweep-flag,x,y:绘制圆弧曲线(rx:椭圆X轴方向半径,ry:椭圆Y轴方向半径,x-axis-rotation:x轴旋转角度,large-arc-flag 为 0 的时候表示取小弧度,1 的时候取大弧度,sweep-flag 0 取逆时针方向,1 取顺时针方向下;x,y:终点坐标)
● Vy:画垂直线到指定的Y坐标位置(y:Y轴指定的坐标位置)
● Hx:画水平线到指定的X坐标位置(x:X轴指定的坐标位置)
● Qx1,y1 x,y:二阶贝塞尔曲线(x1,y1:控制点坐标,x,y:终点结束坐标)
● Cx1,y1 x2,y2 x,y:三阶贝塞尔曲线(x1,y1:控制点1坐标,x2,y2:控制点2坐标,x,y:终点结束坐标)
● Tx,y:平滑的二阶贝塞尔曲线,参数只有一个点(x,y),这个点是结束点,控制点是前一个二阶贝塞尔曲线的控制点相对于前一个贝塞尔曲线的结束点的镜像点;(简单理解就是前面路径的终点直接和指定T点坐标直线连接)
● Sx2,y2 x,y:平滑的三阶贝塞尔曲线,参数为(x2,y2 x,y) ,x2,y2 为第二个控制点,x,y为绘制终点,那么第一个控制点则是前一个三阶曲线的第二个控制点相对于前一个三阶曲线终点的镜像点。
属性详解
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:name="用于定义这个 vector drawable 的名字,eg:vectorDemo"
android:width="定义该 drawble 的内部宽度,支持所有的 Android 系统支持的尺寸单位,通常使用 dp,eg:100dp"
android:height="定义该 drawble 的内部高度,支持所有的 Android 系统支持的尺寸单位,通常使用 dp,eg:100dp"
android:viewportWidth="定义矢量图视图的宽度,实际上就是对应 path 路径所使用的数据,eg:100.0"
android:viewportHeight="定义矢量图视图的高度,实际上就是对应 path 路径所使用的数据,eg:100.0"
android:tint="定义该 drawble 线条的颜色,如果定义了改颜色,则在路径里面设置颜色就没有作用了"
android:tintMode="定义 tint 颜色的 Porter-Duff混合模式,默认值为 src_in,取值范围src_in,src_over,src_atop,add,screen,multiply"
android:autoMirrored="设置当系统为 RTL (right-to-left)布局的时候,是否自动镜像该图片"
android:alpha="该图片的透明属性">
<!-- group 元素来把多个 path 放到一起 -->
<group
android:name="定义 group 的名字"
android:rotation="定义该 group 的路径旋转多少度(顺时针旋转)"
android:pivotX="定义缩放和旋转该 group 时候的 X 参考点。该值相对于 vector 的 viewport 值来指定的。"
android:pivotY="定义缩放和旋转该 group 时候的 Y 参考点。该值相对于 vector 的 viewport 值来指定的。"
android:scaleX=" 定义 X 轴的缩放倍数"
android:scaleY="定义 Y 轴的缩放倍数"
android:translateX=" 定义移动 X 轴的位移。相对于 vector 的 viewport 值来指定的"
android:translateY=" 定义移动 Y 轴的位移。相对于 vector 的 viewport 值来指定的">
<!-- path 元素即为需要绘制的图形/路径,里面的 pathData 就是矢量图的路径数据 -->
<path
android:name="定义该 path 的名字,这样在其他地方可以通过名字来引用这个路径"
android:pathData="矢量图的路径数据,和SVG中d 元素一样的路径信息"
android:strokeWidth="3"
android:fillColor="定义填充路径的颜色,如果没有定义则不填充路径"
android:strokeWidth="定义路径边框的粗细尺寸"
android:strokeAlpha="定义路径边框的透明度"
android:fillAlpha="定义填充路径颜色的透明度"
android:strokeLineCap="设置路径的线头的形状,取值为 butt,round,square 默认是 butt"
android:strokeLineJoin="设置路径交界处的连接方式,取值为 miter、round、bevel 默认是 miter"
android:strokeMiterLimit="设置斜角的上界 默认是 4 (当 strokeLineJoin 设置为 miter 的时候,绘制两条线段以锐角相交的时候,所得的斜面可能相当长,当斜面太长,就会变的不协调。strokeMiterLimit 属性为斜面的长度设置了一个上限。这个属性表示斜面长度和线条长度的比值。当 strokeLineJoin 设置为其他属性时,这个属性是无效的"
android:trimPathStart="从路径起始位置(path 的 M 位置)截取后剩下的内容,取值范围从 0 到 1,比如,取值是 0.3 则截取后的内容就是 原长度 - (原长度*0.3)"
android:trimPathEnd="从路径起始位置位置截取的内容,取值范围从 0 到 1,比如,取值是 0.3,则截取后的内容就是 原长度*0.3"
android:trimPathOffset="其实就是设置开始点的偏移位置(取值 从 0 到 1)1 的话就是开始点和结束的互换了" />
</group>
</vector>
动画
图形转换
单个path
■ 绘制Vector res/rawable中创建文件path1_vector.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="300dp"
android:height="300dp"
android:viewportWidth="200.0"
android:viewportHeight="200.0">
<!-- M 为起点 Z:终点并关闭路径 L:线性 -->
<path
android:name="path1"
android:pathData="M50,100,L85,100,150,100"
android:strokeWidth="3"
android:strokeColor="@android:color/black" />
</vector>
■ 定义动画 res/animator中创建文件path1_anim.xml
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1500"
android:propertyName="pathData"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="M50,100,L85,100, 150,100"
android:valueTo="M50,100,L85,140, 150,100"
android:valueType="pathType" />
■ vector与动画结合 res/drawable中创建文件path1_anim_vector.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/path1_vector">
<target
android:name="path1"
android:animation="@animator/path1_anim" />
</animated-vector>
■ 使用
<ImageView
android:id="@+id/anim_test"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/path1_anim_vector" />
binding.animTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable drawable = binding.animTest.getDrawable();
if (drawable instanceof Animatable) {
if (((Animatable) drawable).isRunning()) {
((Animatable) drawable).stop();
} else {
((Animatable) drawable).start();
binding.animTest.refreshDrawableState();
}
}
}
});
group组合
■ 绘制Vector res/rawable中创建文件path2_vector.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="300dp"
android:height="300dp"
android:viewportWidth="200.0"
android:viewportHeight="200.0">
<group android:name="path2_group">
<!-- M 为起点 Z:终点并关闭路径 L:线性 -->
<path
android:name="path1"
android:strokeWidth="3"
android:strokeColor="@android:color/black"
android:pathData="M50,50 L150,50" />
<path
android:name="path2"
android:strokeWidth="3"
android:strokeColor="@android:color/black"
android:pathData="M50,100 L150,100" />
<path
android:name="path3"
android:strokeWidth="3"
android:strokeColor="@android:color/black"
android:pathData="M50,150 L150,150" />
</group>
</vector>
■ 定义动画 res/animator中创建文件path2_anim1.xml和path2_anim2.xml
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1500"
android:propertyName="pathData"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="M50,50 L150,50"
android:valueTo="M100,50 L150,100"
android:valueType="pathType" />
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1500"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:propertyName="pathData"
android:valueFrom="M50,150 L150,150"
android:valueTo="M100,150 L150,100"
android:valueType="pathType" />
■ vector与动画结合 res/drawable中创建文件path2_anim_vector.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/path2_vector">
<target
android:name="path1"
android:animation="@animator/path2_anim1" />
<target
android:name="path3"
android:animation="@animator/path2_anim2" />
</animated-vector>
■ 使用
<ImageView
android:id="@+id/anim_test"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/path2_anim_vector" />
binding.animTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable drawable = binding.animTest.getDrawable();
if (drawable instanceof Animatable) {
if (((Animatable) drawable).isRunning()) {
((Animatable) drawable).stop();
} else {
((Animatable) drawable).start();
binding.animTest.refreshDrawableState();
}
}
}
});
缩放
● 绘制Vector res/rawable中创建文件start_vector.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="300dp"
android:height="300dp"
android:viewportWidth="200.0"
android:viewportHeight="200.0">
<group
android:name="start_group"
android:pivotX="100"
android:pivotY="100">
<path
android:name="start"
android:fillColor="@color/black"
android:pathData="M100,0,L76,76,L0,78,L60,124,L40,200,L100,175,L160,200,L140,124,L200,78,L124,76,Z" />
</group>
</vector>
● 定义动画 res/animator中创建文件scale_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="3000"
android:propertyName="scaleX"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="0.5"
android:valueTo="1.0"
android:valueType="floatType" />
<objectAnimator
android:duration="3000"
android:propertyName="scaleY"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="0.5"
android:valueTo="1.0"
android:valueType="floatType" />
</set>
● vector与动画结合 res/drawable中创建文件start_scale_anim_vector.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/start_vector">
<target
android:name="start_group"
android:animation="@animator/scale_anim" />
</animated-vector>
● 使用
<ImageView
android:id="@+id/anim_test"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/start_scale_anim_vector" />
binding.animTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable drawable = binding.animTest.getDrawable();
if (drawable instanceof Animatable) {
if (((Animatable) drawable).isRunning()) {
((Animatable) drawable).stop();
} else {
((Animatable) drawable).start();
binding.animTest.refreshDrawableState();
}
}
}
});
平移
● 绘制Vector res/rawable中创建文件start_vector.xml
● 定义动画 res/animator中创建文件translate_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="3000"
android:propertyName="translateX"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="-50"
android:valueTo="50"
android:valueType="floatType" />
<objectAnimator
android:duration="3000"
android:propertyName="translateY"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="-50"
android:valueTo="50"
android:valueType="floatType" />
</set>
● vector与动画结合 res/drawable中创建文件start_translate_anim_vector.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/start_vector">
<target
android:name="start_group"
android:animation="@animator/translate_anim" />
</animated-vector>
■ 使用
<ImageView
android:id="@+id/anim_test"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/start_translate_anim_vector" />
binding.animTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable drawable = binding.animTest.getDrawable();
if (drawable instanceof Animatable) {
if (((Animatable) drawable).isRunning()) {
((Animatable) drawable).stop();
} else {
((Animatable) drawable).start();
binding.animTest.refreshDrawableState();
}
}
}
});
透明度
● 绘制Vector res/rawable中创建文件start_vector.xml
● 定义动画 res/animator中创建文件alpha_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="2000"
android:propertyName="fillAlpha"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="1.0"
android:valueTo="0.0"
android:valueType="floatType" />
</set>
● vector与动画结合 res/drawable中创建文件alpha_anim_vector.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/start_vector">
<target
android:name="start"
android:animation="@animator/alpha_anim" />
</animated-vector>
● 使用
<ImageView
android:id="@+id/anim_test"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/alpha_anim_vector" />
binding.animTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable drawable = binding.animTest.getDrawable();
if (drawable instanceof Animatable) {
if (((Animatable) drawable).isRunning()) {
((Animatable) drawable).stop();
} else {
((Animatable) drawable).start();
binding.animTest.refreshDrawableState();
}
}
}
});
旋转
● 绘制Vector res/rawable中创建文件start_vector.xml
● 定义动画 res/animator中创建文件scale_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="3000"
android:propertyName="scaleX"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="0.5"
android:valueTo="1.0"
android:valueType="floatType" />
<objectAnimator
android:duration="3000"
android:propertyName="scaleY"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="0.5"
android:valueTo="1.0"
android:valueType="floatType" />
</set>
● vector与动画结合 res/drawable中创建文件scale_anim_vector.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/start_vector">
<target
android:name="start_group"
android:animation="@animator/scale_anim" />
</animated-vector>
● 使用
<ImageView
android:id="@+id/anim_test"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/scale_anim_vector" />
binding.animTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable drawable = binding.animTest.getDrawable();
if (drawable instanceof Animatable) {
if (((Animatable) drawable).isRunning()) {
((Animatable) drawable).stop();
} else {
((Animatable) drawable).start();
binding.animTest.refreshDrawableState();
}
}
}
});
路径
● 绘制Vector res/rawable中创建文件trimpath_vector.xml
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="300dp"
android:height="300dp"
android:viewportWidth="200.0"
android:viewportHeight="200.0">
<path
android:name="trimpath"
android:strokeWidth="3"
android:pathData="M20,100,L50,100,L60,50,L80,175,l25,-150,l10,100,L130,100,L180,100"
android:strokeColor="@android:color/black" />
</vector>
● 定义动画 res/animator中创建文件trimpath_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="3000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="trimPathStart"
android:repeatCount="infinite"
android:startOffset="1000"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
<objectAnimator
android:duration="3000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="trimPathEnd"
android:repeatCount="infinite"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
</set>
● vector与动画结合 res/drawable中创建文件trimpath_anim_vector.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/trimpath_vector">
<target
android:name="trimpath"
android:animation="@animator/trimpath_anim" />
</animated-vector>
● 使用
<ImageView
android:id="@+id/anim_test"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/trimpath_anim_vector" />
binding.animTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable drawable = binding.animTest.getDrawable();
if (drawable instanceof Animatable) {
if (((Animatable) drawable).isRunning()) {
((Animatable) drawable).stop();
} else {
((Animatable) drawable).start();
binding.animTest.refreshDrawableState();
}
}
}
});
颜色
● 绘制Vector res/rawable中创建文件start_vector.xml
● 定义动画 res/animator中创建文件color_anim.xml
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="fillColor"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="@android:color/black"
android:valueTo="@android:color/holo_red_light"
android:valueType="colorType" />
● vector与动画结合 res/drawable中创建文件color_anim_vector.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/start_vector">
<target
android:name="start"
android:animation="@animator/color_anim" />
</animated-vector>
● 使用
<ImageView
android:id="@+id/anim_test"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/color_anim_vector" />
binding.animTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable drawable = binding.animTest.getDrawable();
if (drawable instanceof Animatable) {
if (((Animatable) drawable).isRunning()) {
((Animatable) drawable).stop();
} else {
((Animatable) drawable).start();
binding.animTest.refreshDrawableState();
}
}
}
});
注意事项
● path中的pathData变化的动画,要求变化前后的path格式必须一致
eg:(50,100)到(100,100)的直线变成(50,100)到(150,100)的直线动画;原始图pathData=M50,100,H100;(50,100)到(150,100)的直线的pathData可以是M50,100,L85,100,150,也可以是M50,100,H150虽然图形一样,前者的格式和原图pathData格式不一致,会产生crash