动画进阶
VectorDrawable
VectorDrawable是为了让Android支持SVG而诞生的。
- 从大小上来看 : VectorDrawable < SVG < PNG ,(压缩应用大小的一个选择方向,虽然现在也有WebP)
- 加载解析速度上:VectorDrawable 只支持SVG的Path标签,最大的原因就是为了解决SVG解析较慢的问题, 而且Path也是可以绘制所有图形的
- 导入SVG生成VectorDrawable : File -> New -> Vector Asset
- VectorDrawable结构如下
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0" //宽等分
android:viewportHeight="24.0"> //高等分
<path
android:fillColor="#FF000000" // 颜色
//图形数据(路径)
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
</vector>
- Gradle的默认配置添加
vectorDrawables.useSupportLibrary = true
静态使用
-
无状态的控件使用:如ImageView
app:srcCompat="@drawable/vector_test"
-
有状态的控件使用: 如Button
- 通过设置background为Selector,在Selector中使用Vector
- 注意!!!要在该页面的Activity或Fragment中设置兼容支持
static { //设置VectorDrawable兼容支持,否则会闪退 AppCompatDelegate .setCompatVectorFromResourcesEnabled(true); }
动态使用(动画)
VectorDrawable最重点的使用
最后效果预览:
VectorDrawable资源
- group 的 name :路径的标志,做平移,缩放,透明度,旋转这些path不具备的属性动画时要使用
- path 的 name :路径的标志,做Vector特有的属性动画时要使用,如
fillColor
,strokeColor
,pathData
,trimPathStart
,trimPathEnd
-
viewportHeight
: 相当于高度总权重的值,下面的绘制的高度数值也是基于这个值为总量 -
viewportWidth
: 相当于宽度总权重的值,下面的绘制的宽度数值也是基于这个值为总量 -
pathData
: 具体绘制图像的路径数据 -
fillColor
: 填充颜色 -
strokeColor
: 边框颜色
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="100dp"
android:height="100dp"
android:viewportHeight="1024.0"
android:viewportWidth="1025.0">
<group android:name="hollow">
<path
android:name="hollow_path"
android:fillColor="@android:color/darker_gray"
android:pathData="M920.7,870.4C920.7,898.7 897.6,921.6 869.1,921.6L765.8,921.6C737.3,921.6 714.1,898.7 714.1,870.4L714.1,153.6C714.1,125.3 737.3,102.4 765.8,102.4L869.1,102.4C897.6,102.4 920.7,125.3 920.7,153.6L920.7,870.4Z
M920.7,0 L714.1,0C657.1,0 610.8,45.8 610.8,102.4L610.8,921.6C610.8,978.2 657.1,1024 714.1,1024L920.7,1024C977.8,1024 1024,978.2 1024,921.6L1024,102.4C1024,45.8 977.8,0 920.7,0L920.7,0Z"/>
</group>
<group android:name="arrow">
<path
android:name="arrow_path"
android:fillColor="@android:color/darker_gray"
android:pathData="M49.9,563.2 L306.4,563.2C328.6,563.2 339.8,582.1 324,597.5L240,675.9C220.5,695 220.5,724.1 240,743.1 259.5,762.2 291.1,761.2 310.6,742.2L487.2,569C526.2,530.9 526.2,468.9 487.2,430.8 459.6,403.6 338.4,285 310.6,257.9 291.1,238.8 259.5,238.8 240,257.9 220.5,277 220.5,307.9 240,327L324,414.1C339.7,429.5 328.5,460.8 306.3,460.8L49.9,460.8C22.4,460.8 0,485 0,512 0,539 22.4,563.2 49.9,563.2L49.9,563.2Z"/>
</group>
</vector>
ObjectAnimator资源
动画的具体操作
- 路径绘制动画:从开始到结束的路径的动画
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="trimPathStart"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
>
</objectAnimator>
- 路径转换动画: 从一个图形变成另外一个图形
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:androd="http://schemas.android.com/apk/res/android"
androd:duration="3000"
androd:propertyName="pathData"
androd:valueFrom="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z"
androd:valueTo="M 48,54 L 31,54 15,54 10,35 6,23 25,10 32,4 40,10 58,23 54,35 z"
androd:valueType="pathType">
</objectAnimator>
- 颜色转换动画: 实现颜色的渐变(边框颜色就是fillColor变成strokeColor)
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:propertyName="fillColor"
android:valueFrom="@android:color/darker_gray"
android:valueTo="@android:color/holo_red_light"
android:valueType="colorType">
</objectAnimator>
- 上平移动画: !!值得一提的是,平移的距离是和VectorDrawable的
viewportHeight
和viewWidth
挂钩的, 好比Vector的viewportHeight=100,那么我上一50,就等于移动了图形总面积的50%
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:interpolator/overshoot"
android:propertyName="translateY"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="0"
android:valueTo="-300"
android:valueType="floatType"
>
</objectAnimator>
- 剩下的缩放,旋转,透明度和普通的属性动画差不多就不贴出了
Animated-vector资源
VectorDrawable 和 ObjectAnimator的 粘合剂
将动画资源作用到Vector资源的核心
- 预览中箭头左移,正方形上移的动画:
<?xml version="1.0" encoding="utf-8"?>
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_svg_arrow_right_bank"
>
<target
android:name="hollow"
android:animation="@animator/anim_translate_top_iii"/>
<target
android:name="arrow"
android:animation="@animator/anim_translate_right_i"/>
<target
android:name="arrow_path"
android:animation="@animator/anim_color_turn_red_fill"/>
</animated-vector>
- 预览中的红色螺旋绘制动画:
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/ic_svg_icon_helix"
tools:targetApi="lollipop">
<target
android:name="helix"
android:animation="@animator/anim_path_end"/>
<target
android:name="helix"
android:animation="@animator/anim_color_turn_red"/>
</animated-vector>
代码启动
- 首先在布局资源中使用
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
app:srcCompat="@drawable/anim_arrow_bank_play"/>
<TextView
android:id="@+id/tv_set"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:drawableTop="@drawable/anim_three_point_loading"
android:onClick="doClick"
android:scaleType="fitXY"
android:text="三点动画组合"
/>
<TextView
android:id="@+id/tv_helix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:drawableTop="@drawable/anim_helix_play"
android:gravity="center"
android:onClick="doClick"
android:scaleType="fitXY"
android:text="超级螺旋"
/>
- 代码中启动动画:
public void doClick(View view) {
/**
* 这个主要针对pathData路径变化
* 只支持5.0以上的版本
*/
if (view.getId() == R.id.tv_path) {
AnimatedVectorDrawable vectorDrawable = (AnimatedVectorDrawable) getDrawable(R.drawable.anim_square_play);
((TextView) view).setCompoundDrawables(null, vectorDrawable, null, null);
vectorDrawable.start();
} else {
/**
* TextView中获取资源并启动
*/
if (view instanceof TextView) {
Drawable[] drawables = ((TextView) view).getCompoundDrawables();
((Animatable) drawables[1]).start();
}
/**
* ImageView中获取资源并启动
*/
if (view instanceof ImageView) {
((Animatable) ((ImageView) view).getDrawable()).start();
}
}
}
一些理解
优势:
- 理解了SVG中的知识,可以根据路径很好的拆分,就像上面的箭头和正方形就是一个svg图形,然后拆分进行动画
- 路径绘制的优势,UI提供我们需要的SVG路径,我们就可以非常简单的实现路径动画
- 除了路径转换(注意不是路径绘制) 以外,其他都是支持向下兼容到3.0
劣势:
- 资源文件过多,根据具体图像的动画资源,动画粘合剂资源会出现十分多,需要规范好UI制作的svg,抽取出完善的ObjectAnimator来相互组合使用
- 一开始使用会感觉有点繁琐吧,其实我感觉还好,主要看个人吧,如果在自定义View绘制比较弱的话,VectorDrawable提供了很好的解决方案
代码项目Github