五、Android SVG动画

SVG的全称是Scalable Vector Graphics(可缩放矢量图形),它不会因为图像放大而失真,且占用内存小,同时搭配Path动画,能够实现一些意想不到的效果。
Android中的SVG图像又叫Vector图像,它是对原生的SVG进行了简化,利用path来实现绘制。

1、VetcorDrawable

1.1、Vector图形制作

我们可以在svg编辑网页上制作好SVG图像,然后通过Android Studio中的Vector Asset Studio,将SVG转换成Vector。

转换后代码格式大致如下:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="200dp"
    android:height="100dp"
    android:viewportWidth="100"
    android:viewportHeight="50">

    <path
        android:name="bar"
        android:pathData="M50,23 L100,25"
        android:strokeWidth="2"
        android:strokeColor="@android:color/darker_gray" />
</vector>

1.2、vector标签属性

标签 含义
width 图形的具体宽度
height 图形的具体高度
viewportWidth 图形横向被划分的个数
viewportHeight 图形纵向被划分的个数

用于vector图形是矢量图,即无限放大也不会失真,所以要指定其宽高。
同时图形中的坐标值,也不能依据宽高的具体值大小,只是就引入了划分比例大小,即viewportXXX

举例说明:本例中,将大小为200dp x 100dp的图像,划分出100 x 50个小份,每份尺寸为2dp x 2dp;而android:pathData属性中的坐标值,就是相对于这100 x 50个小份所决定的。如坐标(50,50),就对应本图形底部中点。


1.3、path标签属性

1、常用属性
path标签具有以下几个常用属性。

标签 含义
name 声明一个标记,类似于ID,便于对其做动画的时候顺利地找到该节点
strokeWidth 画笔的宽度
fillColor 填充颜色
fillAlpha 填充颜色的透明度
strokeColor 描边颜色
strokeWidth 描边宽度
strokeAlpha 描边透明度
strokeLineJoin 折线拐角形状,取值有miter(结合处为锐角)、round(结合处为圆弧)、bevel(结合处为直线)
strokeLineCap 画出线条的端点的形状(线帽),取值有butt(无线帽)、round(圆形线帽)、square(方形线帽)
strokeMiterLimit 当两条线段以锐角相交的时候,斜面可能很长,视觉上显的不协调。
1、本属性为斜面的长度设置了一个上限,当超出这个上限,它就变成斜角。只在strokeLineJoin为miter时有效。
2、实际上,它表示斜面长度和线条长度的比值,默认值是10,意味着一个斜面的长度不应该超过线条宽度的10 倍。

2、 android:trimPathStart
指定路径的开始位置,取值为0~1。当取值为0时,表示从头部开始;当取值为1时,整条路径不可见。

3、 android:trimPathEnd
指定路径的结束,取值为0~1。当取值为0时,整条路径不可见,当取值为1,整条路径显示完整。当截取的路径超出范围时,会从开始位置继续累计。

4、 android:trimPathOffset
指定结果路径的偏移距离,取值为0~1。当取值为0时,不进行位移,当取值为1,位移整条路径长度。

5、android:pathData
指定图形内容,通过一系列指令和坐标,自动生成对应的图像。


1.4、Vector的常用语法

即Vector中path标签下android:pathData属性里字符串的语法。格式如下:

符号 使用 解释
M = moveto M X,Y 将画笔移动到指定的坐标位置
L = lineto L X,Y 画直线到指定的坐标位置
H = horizontal lineto H V 水平绘制直线到X坐标
V = vertical lineto V Y 垂直绘制直线到Y坐标
Q = quadratic Belzier curve Q X,Y,ENDX,ENDY 二次贝塞曲线
T = smooth quadratic Belzier curve T ENDX,ENDY 二次贝塞曲线
将上一指令的终点作为贝塞尔曲线的起点
C = curveto C X1,Y1,X2,Y2,ENDX,ENDY 三次贝塞曲线
S = smooth curveto S X2,Y2,ENDX,ENDY 三次贝塞曲线
将上一指令的终点作为贝塞尔曲线的起点
A = elliptical Arc A RX,RY,XROTATION,FLAG1,FLAG2,X,Y 弧线
Z = closepath Z 关闭路径

其中A指令绘制一条弧线,各个参数含义如下:

参数 含义
RX,RY 椭圆的半轴大小
XROTATION 椭圆的X轴和水平方向顺时针方向的夹角
FLAG1 只有两个值,1表示大角度弧度,0表示小角度弧度
FLAG2 只有两个值,确定从起始点到终点的方向,1表示顺时针,О表示逆时针

在使用上面的指令时,需要注意以下几点。
1、坐标轴以(0,0)为中心,X轴水平向右,Y轴水平向下。
2、所有指令大小写均可。大写绝对定位,参照全局坐标系;小写相对定位,参照父容器坐标系。
3、指令和数据间的空格可以省略。
4、同一指令出现多次可以只用一个。


1.5、group标签

group标签主要是将同一个Vector文件中,多个Path组成的图像当做一个整体,便于动画执行。包含以下属性:

标签 含义
name 组的名字,用于与动画相关联
rotation 指定该组图像的旋转度数
pivotX 定义缩放和旋转该组时的X参考点,该值是相对于vector 的 viewport值来指定的
pivotY 定义缩放和旋转该组时的Y参考点,该值是相对于vector 的 viewport值来指定的
scaleX 指定该组X轴缩放大小
scaleY 指定该组Y轴缩放大小
translateX 指定该组沿X轴平移的距离
translateY 指定该组沿Y轴平移的距离

1.6、使用VetcorDrawable

gradle文件中配置:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

ImageView or ImageButton

app:srcCompat="@drawable/vector_image"

Button

通过selector来进行设置,并开启下面的设置

static{
    AppCompatDelegate.setCompatVetcorFromResourcesEnabled(true);
}

2、AnimatedVectorDrawable

AnimatedVectorDrawable与VectorDrawable名字上多了一个Animated,这也是它们自己最大的区别,AnimatedVectorDrawable 拥有执行动画的能力。

2.1、AnimatedVectorDrawable使用

1、创建vector图片

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
    <group android:name="left">
        <path
            android:fillColor="#8C9EFF"
            android:pathData="M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3z" />
    </group>
    <group android:name="right">
        <path
            android:fillColor="#8C9EFF"
            android:pathData="M14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4z" />
    </group>
</vector>

2、创建左右动画
左箭头动画

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:interpolator/anticipate_overshoot"
    android:propertyName="translateX"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:valueFrom="0"
    android:valueTo="10"
    android:valueType="floatType"/>

右箭头动画

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:interpolator/anticipate_overshoot"
    android:propertyName="translateX"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:valueFrom="0"
    android:valueTo="-10"
    android:valueType="floatType"/>

3、配置动画粘合剂

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_vector_arrows">
    <target
        android:name="left"
        android:animation="@animator/vector_left_anim" />
    <target
        android:name="right"
        android:animation="@animator/vector_right_anim" />
</animated-vector>

4、为ImageView设置appCompat

<ImageView
     android:layout_width="100dp"
     android:layout_height="100dp"
     android:onClick="animatorStart"
     app:srcCompat="@drawable/anim" />

5、使用动画

public void animatorStart(View view) {
    ImageView imageView = (ImageView) view;
    AnimatedVectorDrawable drawable = (AnimatedVectorDrawable)imageView.getDrawable();
    drawable.start();
}

我们此时会发现,创建一个Vector动画步骤也太繁琐了吧,没关系,谷歌工程师早就帮我们想好了解决办法,通过合并资源,轻松完成上面前3步。

2.2、轨迹动画

这是一种比较常见的动画,比如以下几种(请原谅我盗图):


451f72f752ee777e3df07be3223b47ea.gif
19101361568977583839781636.gif

看起来是不是很炫酷,其实实现起来很简单:
将objectAnimator动画文件android:valueType属性设置为floatTypeandroid:propertyName属性设置为trimPathStarttrimPathEndtrimPathOffset之一,并指定android:valueToandroid:valueTo
当动画执行后,会不断修改上述3个属性的值,以实现各种轨迹动画效果。这3个属性含义上文已经解释,这里就不再提及。

知道了上面的内容,就能很好理解属性动画的定义产生的不同效果了:

1、使用trimPathStart属性,valueFrom:0,valueTo:1
线条从起点缩短到终点,即初始截断部分是0%,从起点开始逐渐扩大到终点,达到100%。

2、使用trimPathStart属性,valueFrom:1,valueTo:0
线条从终点增长到起点,即初始截断部分是100%,从终点开始逐渐缩小到起点,达到0%。

3、使用trimPathEnd属性,valueFrom:0,valueTo:1
线条从起点增长到终点,即初始截断部分是100%,从起点开始逐渐缩小到终点,达到0%。

4、使用trimPathEnd属性,valueFrom:1,valueTo:0
线条从终点缩短到起点,即初始截断部分是0%,从终点开始逐渐扩大到起点,达到100%。

2.3、路径动画

路径动画,相对来说就麻烦一下,但麻烦的在于制作,不是使用,使用时,只需将propertyName设置为pathData,valueType设置为pathType即可。Android就可以从一种图像变成另一种图像。

3、兼容性

3.1、VectorDrawable

Android L,只兼容minSDK>=21的版本
Gradle Plugin 1.5
设备版本>=21——使用Vector
设备版本<21——将Vector转换为png
AppCompat23.2后,VectorDrawable几乎可以兼容大部分使用场景
静态Vector支持Android2.1+
动态Vector支持Android3.0+

3.1、AnimatedVectorDrawable兼容性

1、向下兼容问题
Path Morphing
路径变换动画,在Android pre-L版本下是无法使用的

Path Interpolation
路径插值器,在Android pre-L版本下只能使用系统的插值器,不能自定义

2、向上兼容问题
Path Morphing
路径变换动画,在Android L版本以上需要使用代码配置

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容