Android:获取并制作矢量图动画

来源:互联网 发布:java web经典面试题 编辑:程序博客网 时间:2024/05/19 19:57

通过上一篇文章,我们理解了 Path Data 的命令,这样就可以绘制一些简单的矢量图,也可以看懂一些简单的矢量图。

但是,我们经常所看到的别人的矢量图,都并不简单,那么问题来了,这些复杂的矢量图我们怎么绘制呢? 当然是用一些 svg 编辑器 啦。 这个时候,你是不是感觉很兴奋呢,感觉可以开始画一些高逼格的矢量图。呃…,等等,你好像还是画不出来吧。 没错,其实,我也不会,这是 UI 设计师的工作呀。

矢量图资源

既然自己没这个能力,那就伸手去拿现成的(但是不要养成习惯!)。例如,Android Studio 就可以生成很多矢量图。

“File->New->Vector Asset”

step1

这里写图片描述

然后点击小机器人图标

这里写图片描述

可以看到,这里的矢量图其实还是很多的。

不过问题又随之而来了,这些矢量图都是黑白色的,能不能改下颜色呢?当然能,可以设置 tint 属性,例如

    <ImageView        android:tint="@color/colorPrimary"        android:src="@drawable/ic_archive_black_24dp"        android:layout_width="100dp"        android:layout_height="100dp"/>

我们给 ImageView 设置了 android:tint 属性,这个时候,图片就不再是黑白色了。

这里写图片描述

喜欢搞事的你肯定不满足这点图标数量,肯定还想拥有更多的选择,那我就推荐 阿里巴巴矢量图库,这下就问你满不满足。

对PathData做转换

既然已经可以绘制PathData了,那么也应该可以对PathData做转换(缩放,旋转,位移),这个在Android中是用< group >标签包裹 < path >,然后对 < group > 做转换来实现的。 一个 < group > 可以包含多个 < path >,那么在做转换的时候,可以同时对多个 < Path > 应用转换。

< group > 转换属性如下
1. android:pivotX, andoid:pivotY: 缩放,旋转的 x 轴和 y 轴的中心点,默认为原点(0,0)。
2. android:rotation:旋转角度,默认为0
3. android:scaleXandroid:scaleY:x 轴和 y 轴的缩放的比例,默认为1
4. android:translateXandroid:translateY:x 轴和 y 轴的位移距离,默认为0

例如,我现在画一个播放按钮

<?xml version="1.0" encoding="utf-8"?><vector    xmlns:android="http://schemas.android.com/apk/res/android"    android:width="24dp"    android:height="24dp"    android:viewportHeight="24"    android:viewportWidth="24">    <path        android:fillColor="@color/colorPrimary"        android:pathData="M 6,6 L 18,12 6,18Z"/></vector>

播放按钮

那么,我要让这个图形旋转90°

<?xml version="1.0" encoding="utf-8"?><vector    xmlns:android="http://schemas.android.com/apk/res/android"    android:width="24dp"    android:height="24dp"    android:viewportHeight="24"    android:viewportWidth="24">    <group        android:pivotX="12"        android:pivotY="12"        android:rotation="90">        <path            android:fillColor="@color/colorPrimary"            android:pathData="M 6,6 L 18,12 6,18Z"/>    </group></vector>

转换90

如上面所说,我们需要一个 < group > 包裹 < path >,然后设置旋转中心点,然后设置旋转角度。

AnimatedVectorDrawable

AnimatedVectorDrawable 给矢量图添加属性动画,属性动画操作的是属性,也就是说 AnimatedVectorDrawbale 操作的是矢量图的属性。你可以用三个文件定义一个动画,或者只用一个文件定义一个动画。

多文件定义动画

三个文件包括
1. 一个 VectorDrawable 的 XML 文件
2. 一个 AnimatedVectorDrawable 的 XML 文件
3. 属性动画的 XML 文件 (ObjectAnimator 或者 AnimatorSet)

说起来比较抽象,举个例子

首先,我从 Android Studio 的 Vector Asset 导出一个笑脸图片,然后稍微整理了下,用重新命名为 satisfied.xml,这个作为动画的起始图片。

<vector xmlns:android="http://schemas.android.com/apk/res/android"        android:width="24dp"        android:height="24dp"        android:viewportHeight="24.0"        android:viewportWidth="24.0">    <group        android:name="group_satisfied"        android:pivotX="12.0"        android:pivotY="12.0">        <path            android:fillColor="#FF000000"            android:pathData="M11.99,2 C 6.47,2 2,6.48 2,12 s 4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2z                              M12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z                              M15.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0                              M8.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0z"/>        <path            android:name="satisfied"            android:fillColor="#FF000000"            android:pathData="M12,16c-1.48,0 -2.75,-0.81 -3.45,-2 L6.88,14c0.8,2.05 2.79,3.5 5.12,3.5s4.32,-1.45 5.12,-3.5h-1.67c-0.7,1.19 -1.97,2 -3.45,2"/>    </group></vector>

smile

整个 Path 我没看懂,但是我找到了嘴型的 Path(后面一个 name 为 satisfied 的 path),我把这2个 Path 用一个 < group > 包含,是因为我想让这个2个 Path 做一个旋转转换。

然后,我还导出一个哭脸图片,也整理下了,命名为 dissatisfied.xml,这个作为动画的最终图片。其实这个是没必要导出的,我这里把这个矢量图放出来,是因为我想让大家看明白动画的最终矢量图是什么样的。

<vector xmlns:android="http://schemas.android.com/apk/res/android"        android:width="24dp"        android:height="24dp"        android:viewportHeight="24.0"        android:viewportWidth="24.0">    <group        android:name="group_satisfied"        android:pivotX="12.0"        android:pivotY="12.0">        <path            android:fillColor="#FF000000"            android:pathData="M11.99,2 C 6.47,2 2,6.48 2,12 s 4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2z                              M12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z                              M15.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0                              M8.5,9.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0z"/>        <path            android:name="satisfied"            android:fillColor="#FF000000"            android:pathData="M12,16c-1.48,0 -2.75,-0.81 -3.45,-2 L6.88,14c0.8,2.05 2.79,3.5 5.12,3.5s4.32,-1.45 5.12,-3.5h-1.67c-0.7,1.19 -1.97,2 -3.45,2"/>    </group></vector>

cry

既然已经知道起始的和最终的 VectorDrawable 是什么,那么现在就需要定义一个 AnimatedVectorDrawable,命名为
avd_smile.xml

<?xml version="1.0" encoding="utf-8"?><animated-vector xmlns:android="http://schemas.android.com/apk/res/android"                 android:drawable="@drawable/satisfied">    <target        android:animation="@animator/smile_rotation"        android:name="group_satisfied"/>    <target        android:name="satisfied"        android:animation="@animator/smile_morph"/></animated-vector>

< animated-vector > 的 android:drawable 定义了动画的 VectorDrawable。

< target > 的 android:name 的值为 VectorDrawable 中的 < group > 和 < path > 的 android:name,也就是说,指定了动画的具体目标

< target > 的 android:animation 定了属性动画,这个属性动画由 ObjectAnimator 或者 AnimatorSet 定义。

看下第一个对 < group >动画,animator/smile_rotation.xml

<?xml version="1.0" encoding="utf-8"?><objectAnimator    xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="1000"    android:propertyName="rotation"    android:valueFrom="0"    android:valueTo="360"/>

很简单,就是一个旋转的动画

再看下第二个对 < path >的动画,animator/smile_morph.xml

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="sequentially">    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"                    android:duration="1000"                    android:propertyName="pathData"                    android:valueFrom="M12,16c-1.48,0 -2.75,-0.81 -3.45,-2 L6.88,14c0.8,2.05 2.79,3.5 5.12,3.5s4.32,-1.45 5.12,-3.5h-1.67c-0.7,1.19 -1.97,2 -3.45,2"                    android:valueTo="M12,14 c-2.33,0 -4.32,1.45 -5.12,3.5 L 8.55,17.5 c0.69,-1.19 1.97,-2 3.45,-2s2.75,0.81 3.45,2h1.67c-0.8,-2.05 -2.79,-3.5 -5.12,-3.5"                    android:valueType="pathType"/>    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"                    android:duration="1000"                    android:propertyName="pathData"                    android:valueFrom="M12,14 c-2.33,0 -4.32,1.45 -5.12,3.5 L 8.55,17.5 c0.69,-1.19 1.97,-2 3.45,-2s2.75,0.81 3.45,2h1.67c-0.8,-2.05 -2.79,-3.5 -5.12,-3.5"                    android:valueTo="M12,16c-1.48,0 -2.75,-0.81 -3.45,-2 L6.88,14c0.8,2.05 2.79,3.5 5.12,3.5s4.32,-1.45 5.12,-3.5h-1.67c-0.7,1.19 -1.97,2 -3.45,2"                    android:valueType="pathType"/></set>

这个就有点复杂了,是一个动画集,并且定义了动画的执行顺序为 android:ordering="sequentially ,即顺序执行两个动画。

由于这是对 < path > 执行的动画,因此特别要注意 < objectAnimator > 的 android:valueType 的值为 pathType

最后,就是 android:valueFromandroid:valueTo,分别对应笑脸或者哭脸的嘴型,因为我只想对嘴型做动画。

从 Android Studio 到处的笑脸和哭脸的嘴型 Path 是不能做矢量图动画的,那么要制作成矢量图动画,A 和 B 绘制命令需要满足如下条件
1. A 和 B 要同样数量的命令,并且在每个对应位置,命令类型要一样。
2. 命令后面的参数要完全一样

然后给 ImageView 设置 android:src=@drawable/avd_smile

    <ImageView        android:id="@+id/smile_avd"        android:layout_width="200dp"        android:layout_height="200dp"        android:layout_centerInParent="true"        android:src="@drawable/avd_smile_generator"        android:tint="@color/colorPrimary"/>

然后设置点击 ImageView 启动动画

        findViewById(R.id.smile_avd).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                ImageView imageView = (ImageView) v;                AnimatedVectorDrawable smileDrawable = (AnimatedVectorDrawable) imageView.getDrawable();                smileDrawable.start();            }        });

现在看下效果

笑脸动画

单XML文件定义动画

官网上,给出了一个例子,然后给出了如何用单个 XML 文件生成动画例子,虽然不明觉厉,但是大体上还是看得懂的。不过没有用多文件生成动画来的清晰,但是官网为何要给这个例子呢,因为这个是用工具生成的,但是特么的官网也没告诉我到底可以用什么工具生成。不过我还是找到这个在线工具。接下来,我一步一步告诉大家怎么制作矢量图动画。

首先从Android Studio 的 Vector Drawable 下载一个哭脸矢量图(这个我就不演示了),然后打开https://shapeshifter.design/ 这个网站,选择左下角的 import -> Vector Drawable,导入哭脸的图形。

step1

导入完后,看到效果如下

step2

然后,点击左下角的那个加号按钮,并选择“New group layer”

step3

这个时候,效果是这样的

step4

但是不要被这个层级所迷惑,图中所示的 path,path_1,path_2,grop 是平级的,因此这几个 path 并不在 group 中,不信的话自己双击 group 那一层,看是否这几个 path 会消失。 那么有人会问了,为何在 import vector drawable 之前就先 New group layer,那么我只能说,你试试看。 这点我就要吐槽下,太僵硬了。

那么现在,我们要把 path, path_1, path_2 拖动到 group 中,这个大家应该会操作吧,验证是否拖进去就是,你双击 group ,看那几个 path 是否消失。拖进去后效果如下

step5

一切准备就绪后,首先要明白,我们需要对 group 做旋转动画,对嘴型的 path(也就是 path_2)做动画。

那么首先设置 group 的旋转中心,点击 group 层,然后在右上角设置旋转的中心,设置后效果如下

step6

然后,点击 group 层最右边的类似小闹钟按钮,选择 rotation,然后在右上角设置选择参数,效果如下

这里写图片描述

从截图中的右下方可以看到动画的时间轴,总时间是 300 ms,所以我在右上角中设置 endtime 为 300,并设置 tovalue 为360。到这里,< group > 的旋转效果就设置好,当你点击那个播放按钮的时候,就会看到旋转动画

旋转

然后为嘴型那个 path(也就是 path_2 层)设置矢量图动画,点击 path_2 层的右边的类似小闹钟按钮,然后选择 pathData,然后同上在右上角看到设置pathData数据

这里写图片描述

endTime 同样设置为了 300,那么这个 toValue 是关键,决定最终效果,刚刚我们不是从 Android Studio 下载了个笑脸矢量图嘛,那么这个就设置笑脸图形中的那个嘴型 Path。

到这了,你可以再点击播放按钮,不过首先,你得把事件坐标轴调整到 0ms 的地方。

这里写图片描述

到这了,你是不是有点兴奋了,接下来要导出来,点击左下角的 “export” ,然后选择 “Animated Vector Drawable”

这里写图片描述

你以为这就完了吗?你把这个导出文件放到 res/drawable 目录下,然后给上面例子中的 ImageView 设置 android:src 试试? Boom ! App Crash! 那我就来告诉你,有哪几处错误,打开导出的文件,如果截图中就是错误点

这里写图片描述

刚才说过,要对 group 旋转,要对 path_2 做动画,因此第一个红色圈,应为 group 名字,第一个红色圈应为 path_2 的名字,也就是如下截图中所示

这里写图片描述

改完名字后,然后就是那个 valueFrom 和 valueTo 的错误,有的兄弟会认为,这不就是笑脸和哭脸的嘴型的 Path 吗? 那你赋值粘贴进去试试,保证又是一声 Boom~ 。我当时看到 app crash 的心情就是想把这个网站的作者找出来到有关部门喝喝茶,因为我差点损失了一个键盘。

好了,回归正题,这2个值如何设置呢?我们再回到那个网站的界面,点击时间轴上关于 path_2 动画的那一条线

这里写图片描述

按图中所示,把右上角那个 valueFrom 和 valueTo 复制粘贴到我们到处的文件中,这样才叫真正的完成。修改后的到处文件代码如下

<animated-vector    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:aapt="http://schemas.android.com/aapt">    <aapt:attr name="android:drawable">        <vector            xmlns:android="http://schemas.android.com/apk/res/android"            android:width="24dp"            android:height="24dp"            android:viewportWidth="24"            android:viewportHeight="24">            <group                android:name="group"                android:pivotX="12"                android:pivotY="12">                <path                    android:name="path"                    android:pathData="M 15.5 9.5 M 14 9.5 C 14 8.672 14.672 8 15.5 8 C 16.328 8 17 8.672 17 9.5 C 17 10.328 16.328 11 15.5 11 C 14.672 11 14 10.328 14 9.5"                    android:fillColor="#FF000000"/>                <path                    android:name="path_1"                    android:pathData="M 8.5 9.5 M 7 9.5 C 7 8.672 7.672 8 8.5 8 C 9.328 8 10 8.672 10 9.5 C 10 10.328 9.328 11 8.5 11 C 7.672 11 7 10.328 7 9.5"                    android:fillColor="#FF000000"/>                <path                    android:name="path_2"                    android:pathData="M 11.99 2 C 6.47 2 2 6.48 2 12 C 2 17.52 6.47 22 11.99 22 C 17.52 22 22 17.52 22 12 C 22 6.48 17.52 2 11.99 2 Z M 12 20 C 7.58 20 4 16.42 4 12 C 4 7.58 7.58 4 12 4 C 16.42 4 20 7.58 20 12 C 20 16.42 16.42 20 12 20 Z M 12 14 C 9.67 14 7.68 15.45 6.88 17.5 L 8.55 17.5 C 9.24 16.31 10.52 15.5 12 15.5 C 13.48 15.5 14.75 16.31 15.45 17.5 L 17.12 17.5 C 16.32 15.45 14.33 14 12 14 Z"                    android:fillColor="#FF000000"/>            </group>        </vector>    </aapt:attr>    <target android:name="group">        <aapt:attr name="android:animation">            <objectAnimator                xmlns:android="http://schemas.android.com/apk/res/android"                android:propertyName="rotation"                android:duration="300"                android:valueFrom="0"                android:valueTo="360"                android:valueType="floatType"                android:interpolator="@android:interpolator/fast_out_slow_in"/>        </aapt:attr>    </target>    <target android:name="path_2">        <aapt:attr name="android:animation">            <objectAnimator                xmlns:android="http://schemas.android.com/apk/res/android"                android:propertyName="pathData"                android:duration="300"                android:valueFrom="M 11.99 2 C 6.47 2 2 6.48 2 12 C 2 17.52 6.47 22 11.99 22 C 17.52 22 22 17.52 22 12 C 22 6.48 17.52 2 11.99 2 Z M 12 20 C 7.58 20 4 16.42 4 12 C 4 7.58 7.58 4 12 4 C 16.42 4 20 7.58 20 12 C 20 16.42 16.42 20 12 20 Z M 12 14 C 9.67 14 7.68 15.45 6.88 17.5 L 8.55 17.5 C 9.24 16.31 10.52 15.5 12 15.5 C 13.48 15.5 14.75 16.31 15.45 17.5 L 17.12 17.5 C 16.32 15.45 14.33 14 12 14 Z"                android:valueTo="M 11.99 2 C 6.47 2 2 6.48 2 12 C 2 17.52 6.47 22 11.99 22 C 17.52 22 22 17.52 22 12 C 22 6.48 17.52 2 11.99 2 Z M 12 20 C 7.58 20 4 16.42 4 12 C 4 7.58 7.58 4 12 4 C 16.42 4 20 7.58 20 12 C 20 16.42 16.42 20 12 20 Z M 12 16 C 10.52 16 9.25 15.19 8.55 14 L 6.88 14 C 7.68 16.05 9.67 17.5 12 17.5 C 14.33 17.5 16.32 16.05 17.12 14 L 15.45 14 C 14.75 15.19 13.48 16 12 16 Z"                android:valueType="pathType"                android:interpolator="@android:interpolator/fast_out_slow_in"/>        </aapt:attr>    </target></animated-vector>

这个时候,你再把这个到处文件设置为 ImageView 的 android:src 属性,你就可以看到效果了

最终效果

结束

我相信大家在刚接触矢量图的时候是懵逼的,更别提如何去制作矢量图动画,当然这也也是我的疑惑。 通过本篇文章,我们对如何生成矢量图,以及如何制作矢量图动画,心里就有个底了。

本篇文章,并没有把 VectorDrawable 和 AnimatedVectorDrawable 讲完全,由于篇幅限制,留在下一篇讲。

参考

https://developer.android.com/guide/topics/graphics/vector-drawable-resources.html
http://www.androiddesignpatterns.com/2016/11/introduction-to-icon-animation-techniques.html
https://shapeshifter.design/

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 我的世界被banip怎么办 dnf深渊宝珠出了怎么办 吞噬魔4个球吃了怎么办 dnf没有支援兵了怎么办 家里没通天然气怎么办 苹果6p16g不够用怎么办 魅蓝手机内存不够用怎么办 3dmax灯光全黑怎么办 高压15o低压1oo怎么办 源码一位乘法中c怎么办 怀孕搬了重东西怎么办 深蹲力量不涨怎么办 ps4连接显示器分辨率低怎么办 大疆失去链接后怎么办 脑袋被锤了几拳怎么办 华为手机变板砖怎么办 电脑网页打开很慢怎么办 网页加载速度太慢.怎么办 cad字显示不出来怎么办 dell笔记本打不开机怎么办 手机系统界面已停止运行怎么办 大石退出菊丸怎么办 word空白页面突然变大了怎么办 高速上车胎爆了怎么办 没有定速巡航跑长途怎么办 惠普笔记本驱动无法安装怎么办 狙击手遇到热追踪导弹怎么办 做完卷腹脖子疼怎么办 医疗设备销售遭遇瓶颈怎么办 给顾客加油加超了怎么办 卡密码输错两次怎么办 擤鼻涕耳朵会响怎么办 鼻子里有血丝是怎么办 怀孕8周上火了怎么办 鼻炎犯了鼻涕流不停怎么办 擤鼻涕眼睛肿了怎么办 感冒咳嗽鼻子不通气怎么办 宝宝感冒不会擤鼻涕怎么办 新生儿鼻腔里有鼻涕怎么办 宝宝鼻腔有鼻涕出不来怎么办 怀孕的人感冒了怎么办