Android SVG和Lottie库播放动画(Json)

Android SVG和Lottie库播放动画(Json)

AE-----→Json
安卓调用.json文件

一、SVG

SVG是Android 5.0中新加入的一个新特性。

从5.0开始android也开始支持SVG图了,这使得我们可以实现更多的好看的动画。

什么是SVG?

SVG的全称是Scalable Vector Graphics,叫可缩放矢量图形。它和位图(Bitmap)相对,SVG不会像位图一样因为缩放而让图片质量下降。下面这个图片展示了SVG和位图的区别,左边的位图在放大后出现了锯齿,而右边的SVG任然清晰。

为什么要使用SVG

  1. SVG 可被非常多的工具读取和修改(比如记事本),由于使用xml格式定义,所以可以直接被当作文本文件打开,看里面的数据;
  2. SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强,SVG 图就相当于保存了关键的数据点,比如要显示一个圆,需要知道圆心和半径,那么SVG 就只保存圆心座标和半径数据,而平常我们用的位图都是以像素点的形式根据图片大小保存对应个数的像素点,因而SVG尺寸更小;
  3. SVG 是可伸缩的,平常使用的位图拉伸会发虚,压缩会变形,而SVG格式图片保存数据进行运算展示,不管多大多少,可以不失真显示;
  4. SVG 图像可在任何的分辨率下被高质量地打印;
  5. SVG 可在图像质量不下降的情况下被放大;
  6. SVG 图像中的文本是可选的,同时也是可搜索的(很适合制作地图);
  7. SVG 可以与 Java 技术一起运行;
  8. SVG 是开放的标准;
  9. SVG 文件是纯粹的 XML;

使用SVG

  1. 可以用SVG图片直接转换成Android可用格式。

    我们可以通过上面的变动手动把普通SVG转成android用的VectorDrawable,或者我们可以用这个网站自动完成转换 http://inloop.github.io/svg2android/

  2. 自己使用代码制作。

用下面的列子来介绍相关的标签

    vector_drawable.xml
    
    <vector xmlns:android="http://schemas.android.com/apk/res/  android"
        android:width="200dp"
        android:height="200dp"
        android:viewportHeight="1000"
        android:viewportWidth="1000">
         <group
            android:name="rotation"
            android:pivotX="500.0"
            android:pivotY="500.0"
            android:rotation="0.0">
            <path
                android:name="vector"
                android:fillColor="#00ffff"
                android:pathData="M67,750 L500,0  500,0  933,750 67,750  M146,853 A 0.1,500 0 0 1 146,148 M146,148 A 500,0.1 0 0 1 851,148  M851,148 A 0.1,500 0 0 1 851,853 M851,853 A 500,0.1 0 0 1 146,853" />
        </group>
    </vector>

注意到和普通SVG图内容不同地方在与viewBox那变成了 viewportWidth, viewportHeight .

viewportWidth , viewportHeight 就相当于画这个SVG的画布大小。

width和height是规定这个SVG图像最终的显示大小的,一般用dp表示。

第二个不同是有一个普通SVG里的fill到android里要变成fillColor,这里就是SVG图像填充的颜色。

第三点不同是,普通SVG的path的数据是d开头的标签,在android里要写成pathData。

综上所述,只要把viewBox的大小改成viewport的大小,把填充颜色的fill改成fillColor,把Path中的d,改成pathData就行了。
android:name="rotation" 为group 和 path 加上 name 属性 是为了后面能便于加上动画。

android:pathData="M67,750 L500,0  500,0  933,750 67,750  M146,853 A 0.1,500 0 0 1 146,148 M146,148 A 500,0.1 0 0 1 851,148  M851,148 A 0.1,500 0 0 1 851,853 M851,853 A 500,0.1 0 0 1 146,853"

M = moveto 相当于 android Path 里的moveTo(),用于移动起始点
L = lineto 相当于 android Path 里的lineTo(),用于画线
H = horizontal lineto 用于画水平线
V = vertical lineto 用于画竖直线
C = curveto 相当于cubicTo(),三次贝塞尔曲线
S = smooth curveto 同样三次贝塞尔曲线,更平滑
Q = quadratic Belzier curve quadTo(),二次贝塞尔曲线
T = smooth quadratic Belzier curveto 同样二次贝塞尔曲线,更平滑
A = elliptical Arc 相当于arcTo(),用于画弧
Z = closepath 相当于closeTo(),关闭path

把制作好的SVG图片放置在 drawable 目录下就可以用了。

<ImageView
    android:layout_width="250dp"
    android:layout_height="300dp"
    android:src="@drawable/vector_drawable"
    android:id="@+id/iv_main"/>

animated-vector

animated-vector 可以去创建一个矢量资源的动画。

同样的,创建出来的 vector_animation.xml 放置在 drawable 下。

animated-vector.xml

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
             android:drawable="@drawable/vector_drawable" >

<target
        android:name="vector"
        android:animation="@anim/vector_anim" />

<target
        android:name="rotation"
        android:animation="@anim/vector_rotation" />
</animated-vector>

android:drawable="@drawable/vector_drawable" 设置矢量资源文件。

target 设置动画,第一个为 @drawable/vector_drawable 下 name 为 vector 设置 动画。第二个 同理。

以下是动画效果文件: (动画文件放置在 anim 文件目录下)

vector_anim.xml 这个是制作了一个变形动画

<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
        android:duration="3000"
        android:propertyName="pathData"
        android:valueFrom="M67,750 L500,0 500,0 933,750 67,750        M146,853 A 0.1,500 0 0 1 146,148 M146,148 A 500,0.1 0 0 1 851,148  M851,148 A 0.1,500 0 0 1 851,853 M851,853 A 500,0.1 0 0 1 146,853"
        android:valueTo="M147,853 L147,147 853,147 853,853 147,853    M146,853 A 0.1,500 0 0 1 146,148 M146,148 A 500,0.1 0 0 1 851,148  M851,148 A 0.1,500 0 0 1 851,853 M851,853 A 500,0.1 0 0 1 146,853"
        android:valueType="pathType" />

<objectAnimator
        android:startOffset="3000"
        android:duration="3000"
        android:propertyName="pathData"
        android:valueFrom="M147,853 L147,147 853,147 853,853 147,853    M147,853 A 0.1,500 0 0 1 147,147 M147,147 A 500,0.1 0 0 1 853,147  M853,147 A 0.1,500 0 0 1 853,853 M851,853 A 500,0.1 0 0 1 147,853"
        android:valueTo="M147,853 L147,147 853,147 853,853 147,853      M147,853 A 500,500 0 0 1 147,147 M147,147 A 500,500 0 0 1 853,147  M853,147 A 500,500 0 0 1 853,853 M853,853 A 500,500 0 0 1 147,853"
        android:valueType="pathType" />
</set>

vector_rotation.xml 这个是制作了一个旋转动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
    android:duration="6000"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="1440" />
</set>

使用该动画:

<ImageView
    android:layout_width="250dp"
    android:layout_height="300dp"
    android:src="@drawable/vector_animation"
    android:id="@+id/iv_main"/>

开启动画的代码:

final ImageView iv = (ImageView) findViewById(R.id.iv_main);
    iv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(iv.getDrawable() instanceof Animatable){
                //开始动画
                ((Animatable) iv.getDrawable()).start();
            }
        }
    }); 

效果如下:



二、Lottie库播放动画

Android 5.x 之后提供了对 SVG 的支持,通过 VectorDrawable、AnimatedVectorDrawable 的结合可以实现一些稍微复杂的动画,但是兼容性是一个问题,不过整个实现流程非常麻烦,每次全新实现一个动画都得重头来过,最最关键的是,如果一个公司下的 App,iOS 也要实现一套一样的动画,资源的占用就显得过大了。

而 Airbnb 开源的这个项目完美的解决以上难题

假设我们要做一个引导页面的欢迎动画,这个一般设计师会用 Adobe 旗下的 After Effects (简称 AE)来做个动画出来,设计师用 AE 做个动画比工程师用代码去实现一个动画要快的多的多,调整起来也很方便,之后 AE 上有一款插件叫做 Bodymovin,这个插件也比较屌,可以直接根据 AE 上的动画文件导出 json 文件,这个 json 文件描述了该动画的一些关键点的座标以及运动轨迹,之后我们在项目中引用 Lottie 开源库,在布局文件中简单的加上这么一句就完美的实现了。

在项目的build.gradle文件中加入:

dependencies {  
  compile 'com.airbnb.android:lottie:1.0.1'
  ...
}

使用Lottie

Lottie 支持Jellybean (API 16)及以上的系统,使用这个Lottie应该把 xxxxx.json 文件放在 app/src/main/assets 目录下。

以下例子中把O.json文件放在规定的目录下。

最简单的使用方式是直接在布局文件中添加:

<com.airbnb.lottie.LottieAnimationView
        android:id="@+id/animation_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:lottie_fileName="O.json"
        app:lottie_loop="true"
        app:lottie_autoPlay="true" />

或者

布局文件中:
<com.airbnb.lottie.LottieAnimationView
        android:id="@+id/animation_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

-----------------------------------------------------
代码中:
LottieAnimationView animationView = (LottieAnimationView) findViewById(R.id.animation_view);
animationView.setAnimation("O.json");
//设置是否循环播放
animationView.loop(true);
//播放动画
animationView.playAnimation();

注意的是:这方法将在后台线程异步加载数据文件,并在加载完成后开始渲染显示动画.

效果如图:

可以通过API控制动画,并且设置一些监听

animationView.addAnimatorUpdateListener((animation) -> {
    // Do something.
});

也可以使用以下方法进行对动画的设置:

btnStop.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //animationView.isAnimating()动画是否在播放
            if (animationView.isAnimating()) {
                //动画停止
                animationView.cancelAnimation();
            }
        }
    });

在使用遮罩的情况下,LottieAnimationView 使用 LottieDrawable来渲染动画.如果需要的话,你可以直接使用drawable形式:

final LottieDrawable drawable = new LottieDrawable();
    LottieComposition.fromAssetFileName(this, "O.json", new LottieComposition.OnCompositionLoadedListener() {
        @Override
        public void onCompositionLoaded(LottieComposition composition) {
            drawable.setComposition(composition);
            drawable.loop(true);
            drawable.playAnimation();
        }
    });

如果你需要频发使用某一个动画,可以使用LottieAnimationView内置的一个缓存策略:

animationView.setAnimation("O.json", LottieAnimationView.CacheStrategy.Strong);
public enum CacheStrategy {
    None,
    Weak,
    Strong
}

其中CacheStrategy的值可以是Strong,Weak或者None,它们用来决定LottieAnimationView对已经加载并转换好的动画持有怎样形式的引用(强引用/弱引用).


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章