动画学习笔记

逐帧动画(frame-by-frame animation)

原理:就是把一个完整的动画拆分成一张张单独的图片,然后将它们连贯起来进行播放

补间动画(tweened animation)

原理:对View进行一系列的动画操作,包括淡入淡出、缩放、平移、旋转四种

缺点:

  1. 只能作用在View上,不能对非View对象进行操作,比如说有一个Point对象用于管理坐标,然后我希望通过修改Point,在onDraw()中根据Point来进行绘制。这种对非View对象的操作补间动画就无法实现。

  2. 只能实现移动、缩放、旋转、淡入淡出这四种动画操作,其实补间动画就是使用硬编码的方式来完成的,功能限定死就是这些,没有扩展性可言。

  3. 只改变了View的显示效果,而没有真正改变View的属性(位置)

也就是因为以上的几点原因,出现了属性动画,解决了上述的问题

属性动画(property animation)

原理:是一种不断对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性

ValueAnimator

对一个值进行平滑的动画过渡,然后你可以添加监听在这个过程中做一些你想做的事情
比如:

ValueAnimator animator = ValueAnimator.ofInt(0,200);
        animator.setDuration(2000);  //设置持续时间
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int value = (int) valueAnimator.getAnimatedValue();
                Log.d("TAG","current value = " + value);
            }
        });
        animator.start();
ValueAnimator animator = ValueAnimator.ofFloat(1f,5f,0f,10f);
        animator.setDuration(2000);  //设置持续时间
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float value = (float) valueAnimator.getAnimatedValue();
                Log.d("TAG","current value = " + value);
            }
        });
        animator.start();

ValueAnimator最常用的应该就是 ofFloat()ofInt()
这两个方法了。
此外还可以调用 setStartDelay() 来设置动画延迟播放的时间
setRepeatCount()setRepeatMode() 方法设置动画循环播放的次数以及循环播放的模式,循环模式包括 RESTART
REVERSE 两种:重新播放和倒序播放的意思

ObjectAnimator

与 ValueAnimator 不同的是 ObjectAnimator 可以直接对任意对象的任意属性进行动画操作,比如说View的alpha属性。

不过虽然ObjectAnimator会更常用一些,但它其实是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成(应该在ValueAnimator对一个值进行平滑过渡时,在监听方法内操作View的属性)。

比如:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
animator.setDuration(5000);  
animator.start();  

或

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
animator.setDuration(5000);  
animator.start(); 

这里的第一个参数传入的是要操作的View,第二个参数是想对该对象的哪个属性进行动画操作。

第二个参数可以传什么样的值呢?
可以传任意值! ObjectAnimator 的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的setget方法,所以可以传任意值,只要这个值有setget方法就OK。

组合动画

实现组合动画功能主要借助 AnimatorSet 这个类,这个类提供了一个play()方法,向这个方法中传入一个Animator对象将会返回一个 AnimatorSet.Builder 的实例, AnimatorSet.Builder 中包含以下四个方法:

  • after(Animator anim) 将现有动画插入到传入的动画之后执行

  • after(long delay) 将现有动画延迟指定毫秒后执行

  • before(Animator anim) 将现有动画插入到传入的动画之前执行

  • with(Animator anim) 将现有动画和传入的动画同时执行

下面是示例代码,效果是让TextView先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出效果,就可以这样写:

ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);  
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
AnimatorSet animSet = new AnimatorSet();  
animSet.play(rotate).with(fadeInOut).after(moveIn);  
animSet.setDuration(5000);  
animSet.start();  

可以看到,这里先是把三个动画对象创建出来,然后new出一个 AnimatorSe t对象后将这三个动画对象进行播放排序。

Animator监听器

有些时候,我们希望可以监听到动画的各种事件,比如动画何时开始,何时结束,然后在开始或结束的时候去执行一些逻辑,Animator类中提供了一个addListener()方法,这个方法接收一个AnimatorListener,我们只要去实现这个AnimatorListener就可以监听动画的各种事件了。

因为ObjectAnimator继承自ValueAnimatorValueAnimator又继承自Animator,而AnimatorSet也继承自Animator,所以addListener()这个方法算是个通用方法。
ObjectAnimatorValueAnimatorAnimatorSet都可以使用。

示例代码:

anim.addListener(new Animator.AnimatorListener() {
            
            @Override
            public void onAnimationStart(Animator animator) {
                    //动画开始时调用
            }
            
            @Override
            public void onAnimationEnd(Animator animator) {
                   //动画结束时调用
            }

            @Override
            public void onAnimationCancel(Animator animator) {
                   //动画被取消时调用
            }
            
            @Override
            public void onAnimationRepeat(Animator animator) {
                   //动画重复执行时调用
            }
        });

但是有时候我们可能只想监听一个事件,不想监听那么多,要把四个接口全部实现一遍就显得非常繁琐,为此,Android提供了一个适配器类 AnimatorListenerAdapter 使用这个类就可以解决掉实现接口繁琐的问题了,如下:

anim.addListener(new AnimatorListenerAdapter() {  
}); 

anim.addListener(new AnimatorListenerAdapter() {  
    @Override  
    public void onAnimationEnd(Animator animation) {  
    }  
});  

这里我们向addListener()方法传入这个适配器对象,由于AnimatorListenerAdapter中已经将每个接口都实现好了,所以这里不用实现任何一个方法也不会报错。那么如果我想监听动画结束这个事件,就只需要单独重写这一个方法就可以了。

使用XML编写动画

使用代码来编写动画是最常用的、也是最方便的做法,但是某些情况我们会需要使用XML来编写动画,比如将某个通用的动画编写到XML里面,就可以在各个界面中轻松去重用它。

首先需要在res目录下新建一个animator文件夹,所有属性动画的XML文件都应该存放在这个文件夹。然后XML文件中一共可以使用三种标签:

  • 对应代码中的ValueAnimator

  • 对应代码中的ObjectAnimator

  • 对应代码中的AnimatorSet

比如我们想实现一个从0到100平滑过渡的动画,可以这样写:

  

而如果想将一个View的alpha属性从1变0,可以这样写:

 

另外,XML也可以完成复杂的组合动画,比如上面的那个效果:一个View从屏幕外移动进来,然后旋转360度,旋转同时进行淡入淡出,可以这样写:

  
  
      
      
  
      
          
          
  
          
              
              
              
              
          
      
 

最后我们怎么调用XML中的代码呢?

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);  
animator.setTarget(view);   //设置动画的作用目标View
animator.start();  

参考自:
1、Android属性动画完全解析(上),初识属性动画的基本用法
2、Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法
3、 Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法

Android属性动画深入分析:让你成为动画牛人
Android应用开发之所有动画使用详解
Android动画,一篇就够

你可能感兴趣的:(动画学习笔记)