Android 动画进阶 VectorDrawable

1,891 阅读6分钟
原文链接: www.jianshu.com

动画进阶

VectorDrawable

VectorDrawable是为了让Android支持SVG而诞生的。

  1. 从大小上来看 : VectorDrawable < SVG < PNG ,(压缩应用大小的一个选择方向,虽然现在也有WebP)
  2. 加载解析速度上:VectorDrawable 只支持SVG的Path标签,最大的原因就是为了解决SVG解析较慢的问题, 而且Path也是可以绘制所有图形的
  3. 导入SVG生成VectorDrawable : File -> New -> Vector Asset
  4. 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>
  1. Gradle的默认配置添加vectorDrawables.useSupportLibrary = true

静态使用

  • 无状态的控件使用:如ImageView

    • app:srcCompat="@drawable/vector_test"
  • 有状态的控件使用: 如Button

    • 通过设置background为Selector,在Selector中使用Vector
    • 注意!!!要在该页面的Activity或Fragment中设置兼容支持

      static {
      //设置VectorDrawable兼容支持,否则会闪退
       AppCompatDelegate
           .setCompatVectorFromResourcesEnabled(true);
      }

动态使用(动画)

VectorDrawable最重点的使用
最后效果预览:


device-2017-03-31-171032.mp4_1490953187.gif

VectorDrawable资源


Vector资源.png
  • group 的 name :路径的标志,做平移,缩放,透明度,旋转这些path不具备的属性动画时要使用
  • path 的 name :路径的标志,做Vector特有的属性动画时要使用,如fillColorstrokeColorpathData, 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的viewportHeightviewWidth 挂钩的, 好比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>

代码启动

  1. 首先在布局资源中使用
<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="超级螺旋"
            />
  1. 代码中启动动画:
 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();
            }
        }
    }

一些理解

优势:

  1. 理解了SVG中的知识,可以根据路径很好的拆分,就像上面的箭头和正方形就是一个svg图形,然后拆分进行动画
  2. 路径绘制的优势,UI提供我们需要的SVG路径,我们就可以非常简单的实现路径动画
  3. 除了路径转换(注意不是路径绘制) 以外,其他都是支持向下兼容到3.0

劣势:

  1. 资源文件过多,根据具体图像的动画资源,动画粘合剂资源会出现十分多,需要规范好UI制作的svg,抽取出完善的ObjectAnimator来相互组合使用
  2. 一开始使用会感觉有点繁琐吧,其实我感觉还好,主要看个人吧,如果在自定义View绘制比较弱的话,VectorDrawable提供了很好的解决方案

代码项目Github