Android 动画总结|8月更文挑战

925 阅读4分钟

这是我参与8月更文挑战的第2天,活动详情查看: 8月更文挑战

借 8 月更文挑战来督促自己,感谢掘金!

一、动画的概念以及分类

掌握动画是 Android 开发的一项基本的技能。动画在某些场景下使用得当,会得到事半功倍的效果。Android 动画从大的方向可以分为视图动画和属性动画,视图动画又可以分为补间动画和帧动画,下面先看一张图:

image.png

视图动画和属性动画的本质上的区别是 是否对对象的属性行了更改, 视图动画的移动仅仅是视觉效果的移动的,该 View 本质上是没有发生移动的。

二、视图动画

视图动画的作用对象是整个 View,比如 TextView、Button等控件,它没有办法对对象的属性进行操作,这是属性动画的功能。

(1)、补间动画

补间动画又可以分成以下几种不同的类型:

  • 平移动画
  • 缩放动画
  • 选择动画
  • 透明度动画

其实大致步骤是差不多的,下面就用平移动画来写一个例子。

  1. 在 res 目录下新建一个 anim 的文件夹。
  2. 在 anim 的文件夹下新建  translate_animation 的文件。
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:repeatCount="0"
    android:toXDelta="500"
    android:toYDelta="500">
  
    <!--上面是平移动画的私有属性属性,以下参数是4种动画效果的公共属性,即都有的属性-->
    
    <!--    
        android:duration="3000" // 动画持续时间(ms),必须设置,动画才有效果
        android:startOffset ="1000" // 动画延迟开始时间(ms)
        android:fillBefore = “true” // 动画播放完后,视图是否会停留在动画开始的状态,默认为true
        android:fillAfter = “false” // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
        android:fillEnabled= “true” // 是否应用fillBefore值,对fillAfter值无影响,默认为true
        android:repeatMode= “restart” // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart|
        android:repeatCount = “0” // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
        android:interpolator = @[package:]anim/interpolator_resource // 插值器,即影响动画的播放速度,下面会详细讲
        -->
  

</translate>

以平移动画为例,fromXDelta 表示在 X 的方向上从哪一个位置开始进行平移(fromXDelta 自然表示从 Y的方向),toXDelta 表示是平移到 X 的某一个位置(toYDelta 同理)。

3.通过 AnimationUtils.loadAnimation() 加载动画,使用代码如下:

val translateAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_animation)
translateAnimation.duration = 3000
  1. 启动动画 button1.startAnimation(translateAnimation)

  2. 为动画设置监听事件

translateAnimation.setAnimationListener(object : Animation.AnimationListener {
   override fun onAnimationStart(animation: Animation?) {
       Log.d("yangchao ", "translateAnimation begin")
   }

   override fun onAnimationEnd(animation: Animation?) {
       Log.d("yangchao ", "translateAnimation in process")
   }

   override fun onAnimationRepeat(animation: Animation?) {
       Log.d("yangchao ", "translateAnimation end")
   }
})

效果如下:

(2)、帧动画

帧动画,顾名思义就是把一张张的图片拼接在一起,形成一个 gif 动图的形式。具体的做法如下:

  • 在 Drawable 的目录下新建一个文件 frame_animation:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
   android:oneshot="false">
   <item
       android:drawable="@drawable/a1"
       android:duration="100" />
   <item
       android:drawable="@drawable/a2"
       android:duration="100" />
   <item
       android:drawable="@drawable/a3"
       android:duration="100" />
   <item
       android:drawable="@drawable/a4"
       android:duration="100" />
</animation-list>
  • a1 - a4 是存放在 drawble 下的图片名称,oneshot 代表是否只播放一次,这里设置的false,表示动画a1 - a4 不停地循环播放。
  • 接下来的代码如下:
// 为 ImageView 设置 Resource,目的是加载之前的动画 XML
imageView.setImageResource(R.drawable.frame_animation)
// 获取 ImageView 的 drawable 对象,并进行强制转化
val animationDraw = imageView.drawable as AnimationDrawable
// 启动动画
animationDraw.start()

三、属性动画

视图动画的本质上是改变 View 视觉效果,例如使用补间动画把 Buttom 从左上角移到右下角,但是我们点击右下角是没有任何反应的。属性动画作用于任意的 Java 对象,不再局限于 View 对象。在一定的时间内不断的对值进行改变,从而实现对象在属性上的动画效果。

属性动画有两个主要的类来进行控制 ValueAnimator 和 ObjectAnimator。

1、ValueAnimator

通过控制值的变化,再不断手动赋给对象的属性,从而实现动画的效果。ValueAnimator 有三个重要的方法:

  • ValueAnimator.ofInt(int valus)
  • ValueAnimator.ofFloat(int valus)
  • ValueAnimator.ofObject(int valus)

前面两个都内置了估值器,第三个需要我们自定义估值器,自定义估值器需要继承 TypeEvaluator 类,重写 evaluate 方法。实例代码如下:

public class PointEvaluator implements TypeEvaluator<Point> {
    @Override
    public Point evaluate(float fraction, Point startValue, Point endValue) {
      // 新值 = 开始值 + (结束值 - 开始值)* 持续时间
        float x = startValue.getX() + (endValue.getX() - startValue.getX()) * fraction;
        float y = startValue.getY() + (endValue.getY() - startValue.getY()) * fraction;
      // 其本质上是从新创建了了个对象
        return new Point(x, y);
    }
}
(1)、插值器与估值器
  • 插值器(Interpolator):决定值的变化模式(匀速,加速)
  • 估值器(TypeEvaluator):决定 值 的具体变化
// 动画初始时的对象,和结束时的对象
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(700, 1000);

ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
       curPoint = (Point) animation.getAnimatedValue();
       invalidate();
   }
});
valueAnimator.start();

2、ObjectAnimator

ObjectAnimator.ofFloat(Object object, String property, float ....values)

对于属性动画,其扩展性在于:不局限于系统限定的动画,可以自定义动画,即自定义对象的属性,并通过操作自定义的属性实现动画。

属性动画的使用主要有以下几项:

四、动画基础总结

视图动画的本质上是对 View 视图的视觉效果,属性动画该则是对对象属性进行操作。