Android动画进阶VectorDrawable

动画进阶

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"> //高等分 
            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最重点的使用
    最后效果预览:

  • 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">
                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">
                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>
    
  • 首先在布局资源中使用
  • <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来相互组合使用