当前位置: 萬仟网 > IT编程>移动>Android > SVG矢量动画

SVG矢量动画

2019年05月11日 07:34  | 萬仟网IT编程  | 我要评论

一、概述

相较于png、jpg等位图通过存储像素点来记录图像,svg (scalable vector graphics)拥有一套自己的语法,通过描述的形式来记录图形。android并不直接使用原始的svg格式图片,而是将其转化为vectordrawable。vectordrawable是一个xml格式的drawable,是矢量图在android中的原始资源,引用方法和png、jpg等其他drawable一样。但是,vectordrawable仍然只是一个静态图片,和png、jpg等没什么区别,如果想让vectordrawable “动”起来,就需要用到animatedvectordrawable。animatedvectordrawable才是真正的矢量动效图,其原理就是把vectordrawable和objectanimator结合起来,通过objectanimator属性动画控制vectordrawable,利用矢量图形的特性,从而达到各种炫酷的效果。

svg动效开发流程


二、开发流程

我们下面以一个解锁动效为例,来讲解矢量图动效开发的整个流程。

(1)svg到vectordrawable

svg源文件由美工制作(sketch、ai等工具均可输出svg),vectordrawable也可以通过svg2android工具直接由svg转化而来。

网址:

工具:

本示例我们需要一个锁的矢量图ic_lock_32dp

  <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="32dp"
        android:height="32dp"
        android:viewportheight="110"
        android:viewportwidth="110">
    
        <group
            android:name="g_lock_arc"
            android:pivotx="38"
            android:scalex="1.0">
            <path
                android:name="lock_arc"
                android:pathdata="m71.6,29v-5.4c0-8.9-7.6-16-17-16s-17,7.2-17,16v29"
                android:strokecolor="#000000"
                android:strokelinecap="round"
                android:strokelinejoin="round"
                android:strokewidth="4" />
        </group>
    
        <path
            android:name="lock_rect"
            android:pathdata="m39,29h32c5.5,0,10,4.5,10,10v32c0,5.5-4.5,10-10,10h39c-5.5,0-10-4.5-10-10v39c29,33.5,33.5,29,39,29z"
            android:strokecolor="#000000"
            android:strokewidth="4" />
    </vector>

矢量图主要是由path和group组成,矢量动画实际上就是通过控制path和group的属性变化来实现动画效果的。

(2)vectordrawable到animatedvectordrawable

有了矢量图,就可以设计矢量动画了。分析上面的解锁动效,整个解锁过程可拆分为两部分

  1. 上曲线(name="lock_arc")线条收缩
  2. 上曲线组(name="g_lock_arc")整体水平翻转

我们设计矢量动画图avd_lock_to_open如下:

  <?xml version="1.0" encoding="utf-8"?>
    <animated-vector
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/ic_lock_32dp" ><!--引用的矢量图-->
        <!--曲线收缩-->
        <target
            android:name="lock_arc"
            android:animation="@anim/anim_lock_to_open_p1" />
        <!--曲线组翻转-->
        <target
            android:name="g_lock_arc"
            android:animation="@anim/anim_lock_to_open_p2" />
    </animated-vector>

分析上面代码

  • android:drawable指定的是我们将对哪个矢量图做动效
  • target标签的android:name指定要对矢量图的哪个部分做动效
  • target标签的android:animation引用一个objectanimator,指定要对该部分做什么动画

anim_lock_to_open_p1通过控制trimpathstart属性对path(name="lock_arc")做了收缩:

  <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <objectanimator
            android:duration="300"
            android:interpolator="@android:anim/accelerate_interpolator"
            android:propertyname="trimpathstart"
            android:startoffset="100"
            android:valuefrom="0"
            android:valueto="0.24"
            android:valuetype="floattype"/>
    </set>

anim_lock_to_open_p2通过控制scalex属性对group(name="g_lock_arc")做了水平翻转:

  <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <objectanimator
            android:duration="400"
            android:interpolator="@android:anim/linear_interpolator"
            android:propertyname="scalex"
            android:valuefrom="1"
            android:valueto="-1"
            android:startoffset="450"
            android:valuetype="floattype"/>
    </set>

通过startoffset可以精确控制两个动画的执行顺序。至此,我们已经写好了animatedvectordrawable。

(3)animatedvectordrawable的使用

animatedvectordrawable本身还是一个drawable,和其他图片的引用方式是一样的。这里我们把它设置给imageview

  <?xml version="1.0" encoding="utf-8"?>
    <framelayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <imageview
            android:id="@+id/img"
            android:layout_gravity="center"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:src="@drawable/avd_lock_to_open"/>
    </framelayout>

矢量动态图不会自动播放,在需要播放的时候执行如下代码

  drawable drawable = mimageview.getdrawable();
    if (drawable instanceof animatable) {
        ((animatable) drawable).start();
    }

至此,一个矢量动效的开发和引用已经全部完成了。但有时候我们不想每次都主动调用start方法来播放动效,而是希望根据控件的状态(如state_pressed)改变自动播放相应的过渡动效,这时就需要用到animated-selector了。

(4)animated-selector用法

在讲解animated-selector之前,我们先看一下selector的用法,它可以根据控件的不同状态显示不同的drawable,如

  <?xml version="1.0" encoding="utf-8" ?>   
    <selector xmlns:android="http://schemas.android.com/apk/res/android">   
    <!-- 默认时的背景图片 -->   
    <item android:drawable="@drawable/pic1" />   
    <!-- 没有焦点时的背景图片 -->   
    <item android:state_window_focused="false"   
    android:drawable="@drawable/pic2" /> 
    <!--获得焦点时的图片背景 -->   
    <item android:state_focused="true"   
    android:drawable="@drawable/pic3" />    
    <!--选中时的图片背景 -->   
    <item android:state_selected="true"   
    android:drawable="@drawable/pic4" />    
    </selector>

但使用selector时,状态切换是瞬间完成的,没有过渡。如果希望在状态切换时增加动效,那就需要用到animated-selector。为了讲解,我们仿照矢量动态图avd_lock_to_open再写一个闭锁的动态图avd_open_to_lock。其中会用到一个矢量图ic_open_32dp和两个objectanimator:anim_open_to_lock_p1、anim_open_to_lock_p2,代码类似,不再展示。我们直接看animated_selector的写法:

  <?xml version="1.0" encoding="utf-8"?>
    <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:id="@+id/state_on"
            android:drawable="@drawable/ic_lock_32dp"
            android:state_checked="true" />
        <item
            android:id="@+id/state_off"
            android:drawable="@drawable/ic_open_32dp" />
        <transition
            android:drawable="@drawable/avd_lock_to_open"
            android:fromid="@id/state_on"
            android:toid="@id/state_off" />
        <transition
            android:drawable="@drawable/avd_open_to_lock"
            android:fromid="@id/state_off"
            android:toid="@id/state_on" />
    </animated-selector>

分析上面代码:

  • item标签指定了确定状态下的drawable
  • transition标签指定了状态切换时执行的矢量动效

通常情况下,我们会手动设置控件的状态,以便在适当的时候显示我们想要的动效。比如,我们希望点击imageview时在两个矢量动效之间切换:

  boolean ischecked = false;
    mimageview.setonclicklistener(new view.onclicklistener() {
         @override
         public void onclick(view v) {
              ischecked = !ischecked;
              inal int[] stateset = {ischecked ? android.r.attr.state_checked : 0};
              mimageview.setimagestate(stateset, true);//设置state_checked状态
          }
    });

使用animated-selector后,我们不再需要主动去调start( )方法来播放动效,只需要设置控件状态即可。

最终效果:

至此,我们已经完成了一套完整的矢量动效开发流程,目录结构如下:

svg开发目录

源码:myapplication.zip


 三、总结

我们已经知道svg动效实际上就是通过控制path或group的属性变化来达到动画效果,下面列出常用的可控属性

 
nametags comment
strokealpha path 定义路径边框的透明度
strokewidth    
strokecolor    
     
     
     
     
     
     
     
     
     
     
     
     
     

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

◎已有 0 人评论

Copyright © 2019  萬仟网 保留所有权利. 粤ICP备17035492号-1
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com