Android Vector(Vector/Vector动画)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rozol/article/details/79743079

Android Vector(Vector/Vector动画)


本文由 Luzhuo 编写,转发请保留该信息.
原文: https://blog.csdn.net/Rozol/article/details/79743079


AppCompat23.2 增加了对Vector(矢量图)的全版本兼容
静态 Vector 支持 Android2.1+
动态 Vector 支持 Android3.0+ (属性动画 Android3.0+ (api>=11))
动态 部分不兼容AndroidL(5.0)以下 (path Morphing)

Vector矢量图简介

PNG(位图) / SVG(矢量图) / Vector差异

  • SVG:
  • Vector: Android中使用
    • 工具:
      • SVG2Android(在线 / SVG转Vector): inloop.github.io/svg2android
      • Android Studio Vector Asset: 右键drawable -> New -> Vector Asset -> Material Icon(自带svg图) / Local file(本地的svg图)
  • Vector只实现了SVG语法的Path标签
  • 大小比较: 5,755B(png) > 2,696(svg) > 1,626(vector)

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">
    <path
        android:name="color"
        android:fillColor="#FF000000"
        android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96z"/>
</vector>
  • 标签:

    • width: Vector的宽
    • height: Vector的高
    • viewportWidth: 把width分成多少等份
    • viewportHeight: 把height分成多少等份
    • name: 起个名字
    • fillColor: 填充颜色
    • strokeAlpha: 线条alpa
    • strokeColor: 线条颜色
    • strokeWidth: 线条宽度
    • strokeLineCap: 线帽 round/square
    • pathData: 路径, 根据路径绘制语法进行绘制
  • 路径绘制语法:

    • M = moveto(M X,Y): 画笔移动到指定位置
    • L = lineto(L X,Y): 画直线到指定位置
    • Z = closepath(): 关闭路径
    • H = horizontal lineto(H X): 画水平线到指定X轴位置
    • V = vertical lineto(V Y): 画垂直线到指定Y轴位置
    • Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY): 2阶贝塞尔曲线
    • C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY): 3阶贝赛尔曲线

VectorDrawable

  • 兼容性:

    • 只兼容minSDK >= 21 (AndroidL 5.0)
    • Gradle Plugin 1.5 增加了5.0以下版本的兼容
      • api >=21 使用原生
      • api <= 21 将Vector转换成PNG
    • AppCompat23.2 增加了对Vector的全版本兼容

      • 静态Vector支持Android2.1+
      • 动态Vector支持Android3.0+ (属性动画 Android3.0+ (api>=11))
    • 动态VectorDrawable的兼容问题(唯一无法向下兼容的):

      • path Morphing (路径转换动画 □ -> ○)
        • 在Android L 以上需要代码配置(demo中start的代码不同)
        • 在Android L 以下无法使用
      • path Interpodation (路径插值器)
        • 在Android L 只能使用系统地插值器(不能自定义)
      • 不支持从Strings.xml中读取

VectorDrawable使用场景

  • Vector(矢量图) vs Bitmap(位图)
    • Vector比较简单时,效率高, Vector非常复杂时, Bitmap效率高
    • Vector适用于icon / button / imageview的图标等小的icon, 或者动画效果; Bitmap在GPU中有重绘缓存功能(Vector没有), 能做频繁的重绘(Vector不能).
    • vector加载速度 > png, 渲染速度 < png.

静态使用

准备工作

  1. 配置module的 build.gradle 文件

    android {
        // ...
        defaultConfig{
            // ...
            vectorDrawables.useSupportLibrary = true
        }
    }
    dependencies{
        // ...
        // > 23.2
        compile 'com.android.support:appcompat-v7:24.2.1'
    }
    
  2. 配置project的 build.gradle 文件

    buildscript{
        dependencies{
            //  > 2.1
            classpath 'com.android.tools.build:gradle:2.2.0'
        }
    }
    
  3. 创建适量图, 放到drawable目录下.

    • (自己编写矢量图, 或者从外部导入svg图, 导入步骤见 Vector: Android中使用)
  4. 在ImageView中使用 app:srcCompat="@drawable/cards" 引用

    • 如果是有状态属性的控件(如:Button), 则通过 android:background + selector 方式引用
  5. 在 布局文件中 含有 vector矢量图 的 Activity 还需要添加一句以下代码

    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
    

Vector的放大(缩小同理)

  • 布局: ImageView一个使用默认(24dp * 24dp)大小, 一个使用限定大小

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:srcCompat="@drawable/static_cards" />
    
        <ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            app:srcCompat="@drawable/static_cards" />
  • 效果:

  • 为什么默认大小是(24dp * 24dp), 因为矢量图就设定的这么大

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
            android:width="24dp"
            android:height="24dp"
            android:viewportWidth="24.0"
            android:viewportHeight="24.0">
        <!-- ... -->
    </vector>

通过选择器给Button设置图片

  • 布局: 通过android:background + selector实现

    <Button
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@drawable/static_bg_btn"/>
  • 选择器: 给选择器的默认和按压状态, 分别设置一张不同的vector矢量图

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:drawable="@drawable/static_image" android:state_pressed="true" />
        <item android:drawable="@drawable/static_cards" />
    
    </selector>
    <!-- 选择器 -->
  • 效果:

动态使用

准备工作

  • 同 静态使用 , 略

vector + 属性动画

  • 布局: 给ImageView设置一个动画粘合剂

    <ImageView
        android:onClick="anim"
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:srcCompat="@drawable/dynamic_move_anim"/>
  • 动画粘合剂(drawable目录下): 用于粘合 属性动画 和 适量图, 使用时会提示要api>21, 不用管该提示, 低版本也可使用

    • drawable设置矢量图
    • 通过targetname选择 矢量路径 ,并使用animation 粘合一个属性动画.

      <?xml version="1.0" encoding="utf-8"?>
      <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
          android:drawable="@drawable/dynamic_move" >
      
          <target
              android:animation="@animator/dynamic_move_left"
              android:name="left" />
      
          <target
              android:animation="@animator/dynamic_move_right"
              android:name="right" />
      
      </animated-vector>
  • 适量图: 如果要将矢量图里多个路径都粘合动画, 就需要使用group标签进行分组

    <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="left">
            <path
                android:fillColor="#FF000000"
                android:pathData="M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3z" />
        </group>
    
        <group android:name="right">
            <path
                android:fillColor="#FF000000"
                android:pathData="M14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4z" />
        </group>
        <!-- group 标签可以对path标签进行分组, 并且group标签中含有path所没有的标签, 并且只有被该标签包裹才能执行动画 -->
    
    </vector>
  • 动画: 属性动画里, 使用沿x轴平移动画, 并使用overshoot插值器

    <?xml version="1.0" encoding="utf-8"?>
    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:propertyName="translateX"
        android:valueFrom="0"
        android:valueTo="10"
        android:duration="1000"
        android:repeatCount="infinite"
        android:repeatMode="reverse"
        android:interpolator="@android:interpolator/overshoot" />
    
    <?xml version="1.0" encoding="utf-8"?>
    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:propertyName="translateX"
        android:valueFrom="0"
        android:valueTo="-10"
        android:duration="1000"
        android:repeatCount="infinite"
        android:repeatMode="reverse"
        android:interpolator="@android:interpolator/overshoot" />
  • 在Activity里执行属性动画

    public void anim(View view){
        ImageView imageView = (ImageView) view;
        Drawable drawable = imageView.getDrawable();
        if(drawable instanceof Animatable){
            ((Animatable)drawable).start();
        }
    }
  • 效果:

  • 以上是位移属性动画, 如果要变色动画的话, 只需在属性动画里配置颜色相关属性即可: (颜色提示需要 api>=14, 不用管, 低版本也能用)

    <?xml version="1.0" encoding="utf-8"?>
    <!-- strokeColor:线条颜色 fillColor:填充颜色-->
    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:propertyName="fillColor"
        android:valueFrom="@android:color/holo_red_dark"
        android:valueTo="@android:color/darker_gray"
        android:duration="5000"
        android:interpolator="@android:interpolator/overshoot"
        android:valueType="intType"/>
  • 还有截取动画:

    <?xml version="1.0" encoding="utf-8"?>
    <!-- trimPathStart 从头开始截取, trimPathEnd 从尾开始截取 -->
    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:propertyName="trimPathStart"
        android:valueFrom="1"
        android:valueTo="0"/>
  • 当然也支持组合动画:

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
    
        <objectAnimator
            android:propertyName="trimPathStart"
            android:valueFrom="1"
            android:valueTo="0"
            android:duration="10000"
            android:repeatCount="infinite"
            android:repeatMode="reverse"
            android:valueType="floatType" />
    
        <objectAnimator
            android:propertyName="strokeColor"
            android:valueFrom="@android:color/holo_red_dark"
            android:valueTo="@android:color/darker_gray"
            android:duration="10000"
            android:repeatCount="infinite"
            android:repeatMode="reverse"
            android:valueType="intType" />
    
    </set>
  • 还有路径动画, 但是只支持Android5.0+ (api>=21).

    <?xml version="1.0" encoding="utf-8"?>
    <!-- 属性动画 路径变换( □ -> ○ ) -->
    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
        android:propertyName="pathData"
        android:valueFrom="M 48,54 L 31,42 15,54 21,35 6,23 25,23 32,4 40,23 58,23 42,35 z"
        android:valueTo="M 48,54 L 31,54 15,54 10,35 6,23 25,10 32,4 40,10 58,23 54,35 z"
        android:valueType="pathType"
        android:duration="3000"/>
    
        <!-- 动态VectorDrawable不支持从Strings.xml中读取<pathData>数据,所以将数据拷贝于此 (兼容问题)-->
    • 使用该动画还需要注意的一个问题, 那就是Activity执行该动画也不一样. (其他均相同)

      @TargetApi(Build.VERSION_CODES.LOLLIPOP)
      public void anim(View view){
          ImageView imageView = (ImageView) view;
      
          // 此处代码不同
          AnimatedVectorDrawable drawable = (AnimatedVectorDrawable) getDrawable(R.drawable.dynamic_pathchange_anim);
          imageView.setImageDrawable(drawable);
          if(drawable != null) drawable.start();
      }
    • 动画里的 valueFrom 是从 vector 里拷贝出来的, 告诉动画从这里开始变. (如果不写的话, 执行时间会不准, 你会发现速度会快很多).

    • 效果:

展开阅读全文

没有更多推荐了,返回首页