Android 动画框架实现

3,849 阅读5分钟

我平时项目开发必备框架

  1. Android上最强网络请求 Net
  2. Android上最强列表(包含StateLayout) BRV
  3. Android最强缺省页 StateLayout
  4. JSON和长文本日志打印工具 LogCat
  5. 支持异步和全局自定义的吐司工具 Tooltip
  6. 开发调试窗口工具 DebugKit
  7. 一行代码创建透明状态栏 StatusBar

这里我说是指的Google对于常用的动画效果进行的封装. 有很多炫酷的效果可以通过这些封装快速实现.

LayoutAnimationController

用于支持列表控件(RecyclerView和ListView)的Item动画效果

属性:

  1. 动画

    传入动画XML文件来决定加载动画

  2. 动画顺序

    有三个值: normal 按照正常顺序 reverse 从最后的控件开始加载动画 random 随机顺序

  3. 延迟时间

    毫秒值单位, 表示每个条目的加载时间相差多少毫秒

  4. 动画插值器

布局动画使用方式有两种:

  1. 布局中引用动画

在anim目录下创建XML

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/animation_set"
    android:animationOrder="normal"
    android:delay="300">
</layoutAnimation>

在布局XML中引用XML动画

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    android:id="@+id/ll_root"
    android:gravity="center"
    android:layoutAnimation="@anim/animation_layout"
    >
  1. 代码中引用动画
//通过加载XML动画设置文件来创建一个Animation对象;
Animation animation=AnimationUtils.loadAnimation(this, R.anim.list_anim);
//得到一个LayoutAnimationController对象;
LayoutAnimationController mLayoutAnimationController = new LayoutAnimationController(animation);
//设置控件显示的顺序;
mLayoutAnimationController.setOrder(LayoutAnimationController.ORDER_REVERSE);
//设置控件显示间隔时间;
mLayoutAnimationController.setDelay(1);
//为ListView设置LayoutAnimationController属性;
mList.setLayoutAnimation(mLayoutAnimationController);

Tip: 注意布局动画要么在onCreate方法中执行, 如果在其他地方执行就需要你手动执行布局对象的invalidate()方法.

该函数属于ViewGroup下的动画效果

void setLayoutAnimation (LayoutAnimationController controller)

LayoutTransitionController

参考网上写法我出现了Crash情况. 并且无法直接运行ExampleDemo. 指向ObjectAnimator的View参数不能为Null, 报空指针异常. 我没有解决故也不做讲解.

不过通过在XML布局中给ViewGroup添加如下属性可以启用默认的动画效果

android:animateLayoutChanges="true"

ViewAnimationUtils

揭示效果也可以看做是控制一个控件的圆角变化动画效果. ViewAnimationUtils这个类只有一个方法:

Animator createCircularReveal (View view, 
                int centerX, 
                int centerY, 
                float startRadius, 
                float endRadius)
// 创建环形显示动画
Animator animator = ViewAnimationUtils.createCircularReveal(mBtnExtract, mBtnExtract.getWidth() / 2, mBtnExtract.getHeight() / 2, mBtnExtract.getWidth() / 4, mBtnExtract.getHeight() / 4);

animator.setInterpolator(new LinearInterpolator());
animator.setDuration(1000);
animator.start();

overridePendingTransition

自定义进入下一个Activity和退出当前Activity的动画XML文件, 不需要考虑兼容问题.

注意一定要在startActivity或者finishd的后面调用才有效.

overridePendingTransition(int enterAnim, int exitAnim); // 0表示不显示动画
  • enterAnim 界面进入动画
  • exitAnim 界面退出动画

ViewPropertyAnimator

视图类View提供一个animate()方法方便快速的设置常用动画

ViewPropertyAnimator animate ()

ViewPropertyAnimator这个类基本上可以设置View的所有属性, 方法看名字就可以全部理解了

其中很多方法有带"By"和不带的同名方法. 带"By"相当于相对属性值, 不带就是绝对属性值.

ViewPropertyAnimator translationX (float value)
ViewPropertyAnimator translationXBy (float value)

Tip: 如果使用链式调用可以同时执行多个动画效果.

view.animate()  
        .scaleX(1)
        .scaleY(1)
        .alpha(1);

监听器

ViewPropertyAnimator setListener (Animator.AnimatorListener listener)

AnimatorListener包含四种回调

// 在动画被取消的时候
abstract void	onAnimationCancel(Animator animation)

// 无论动画是否取消, 结束的时候都会回调
abstract void	onAnimationEnd(Animator animation)

default void	onAnimationEnd(Animator animation, 
                               boolean isReverse) // 是否重复

// 动画重复的时候回调
abstract void	onAnimationRepeat(Animator animation) 

// 动画开始
abstract void	onAnimationStart(Animator animation)

default void	onAnimationStart(Animator animation, 
                                 boolean isReverse) // 动画是否重复

还有一种一次性的回调, 如果ViewPropertyAnimator对象再次执行动画并不会回调. 并且withEndAction()在动画被取消的时候不会回调. 这和onAnimationEnd()不同.

ViewPropertyAnimator withEndAction (Runnable runnable)

ViewPropertyAnimator withStartAction (Runnable runnable)

更新

该回调会在大概每10毫秒执行一次

ViewPropertyAnimator setUpdateListener (ValueAnimator.AnimatorUpdateListener listener)

DynamicAnimation

DynamicAnimation是在API25出现的基于物理运动效果的动画, 属于抽象类. 官方目前只有SpringAnimation继承该类. 使用SpringAnimation的好处是让动画显得不那么生硬, 可能有人会说动画插值器也可以. 但是鉴于动画插值器涉及到坐标轴算法Google为了让更多人能够方便的优化自己的动画效果才出现了DynamicAnimation.

官方说明

以下介绍官方示例


SpringForce spring = new SpringForce(0)
  .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
  .setStiffness(SpringForce.STIFFNESS_LOW);

final SpringAnimation anim = new SpringAnimation(mImag, DynamicAnimation.SCALE_Y)
  .setMinValue(0).setSpring(spring).setStartValue(1);
anim.start();

SpringForce

通过SpringAnimation的方法设置

SpringAnimation setSpring (SpringForce force)

或者不创建SpringForce直接通过SpringAnimation得到一个SpringForce实例也可以

SpringForce getSpring ()

是控制SpringAnimation的力度, 分别控制三种弹性特性

  • 阻尼比例
  • 僵硬程度

创建构造方法

SpringForce (float finalPosition) //  最终位置

SpringForce可以决定动画的最终值却无法决定起始值(默认起始值是当前属性值), 起始值也可以由SpringAnimation设置.

阻尼比例设置(阻尼具体提现在摆动次数)

SpringForce setDampingRatio (float dampingRatio)

SpringForce内部提供四种阻尼比例:

public static final float DAMPING_RATIO_HIGH_BOUNCY = 0.2f;  
 
public static final float DAMPING_RATIO_MEDIUM_BOUNCY = 0.5f; // 默认值
 
public static final float DAMPING_RATIO_LOW_BOUNCY = 0.75f; 
 
public static final float DAMPING_RATIO_NO_BOUNCY = 1f;

僵硬值具体提现在摆动时间上

SpringForce setStiffness (float stiffness)

同样SpringForce也提供了四种僵硬值:

public static final float STIFFNESS_HIGH = 10_000f;
 
public static final float STIFFNESS_MEDIUM = 1500f; // 默认值
 
public static final float STIFFNESS_LOW = 200f;
 
public static final float STIFFNESS_VERY_LOW = 50f;

Spring的构造方法

SpringAnimation (View v,  // 目标视图
                DynamicAnimation.ViewProperty property) // 属性值, 后面将重点讲解

SpringAnimation (View v, 
                DynamicAnimation.ViewProperty property, 
                float finalPosition)

ViewProperty是内部的一个抽象类

从源码可以看出主要作用就是设置属性值

DynamicAnimation提供一系列默认的ViewProperty

TRANSLATION_X
TRANSLATION_Y
TRANSLATION_Z
SCALE_X
SCALE_Y
ROTATION
ROTATION_X
ROTATION_Y
X
Y
Z
ALPHA
SCROLL_X
SCROLL_Y

SpringAnimation在运动时候也可以修改最终位置

void animateToFinalPosition (float finalPosition)

AnimatedStateListDrawable

注意和StateListAnimator有所区分, 限制api21;

StateListAnimator 即 <selector>标签中的item从Drawable换成了animation

<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
 
    <item
        android:id="@+id/on"
        android:state_activated="true">
        <bitmap
            android:src="@drawable/ic_heart_100"/>
    </item>
 
    <item
        android:id="@+id/off">
        <bitmap
            android:src="@drawable/ic_heart_0"/>
    </item>
 
    <transition
        android:fromId="@+id/on"
        android:toId="@+id/off"
        android:drawable="@drawable/animation_emptying">
    </transition>
 
    <transition
        android:fromId="@id/off"
        android:toId="@id/on"
        android:drawable="@drawable/animation_filling">
    </transition>
 
</animated-selector>

item可以指定起始和结束的位图以及触发状态

transition可以指定当触发状态时执行什么动画

更多动画阅读我的其他文章

  • 矢量动画
  • 转场动画
  • ViewAnimator