概述 动画主要分为三种:View动画、帧动画、属性动画,分别介绍:
View动画 View动画的作用对象是View,主要包含平移动画、缩放动画、旋转动画、透明度动画。分别对应TranslateAnimation、ScaleAnimation、RotateAnimation、AlphaAnimation。可以通过XML来实现也可以通过代码,需要注意一点的是View动画最大的缺点是不能交互,View自身的属性并不会发生变化。例如对一个放大的View进行点击,点击区域其实还是原本View的点击区域。
Animation自身的属性 上面提到的属性都是Animation子类特有的属性,Animation自身带有:
duration 设置动画持续时间,单位为毫秒 
fillAfter 如果为true则在动画结束后保持动画结束时的状态 
fillBefore 如果设置为true则在动画结束后还原到动画前的状态 
fillEnabled 和fillBefore效果相同 
repeatCount 动画重复次数 
repeatMode 重复类型,包括reverse和restart两个值,分别是倒序播放和重新播放,必须与repeatCount一起才会有效果,因为这里的意义是回放时的动作 
interpolator 设置插值器,该属性影响动画的速度,可以不指定,默认为加速减速差值器(AccelerateDecelerateInterpolator) 
 
TranslateAnimation 在Xml中定义,fromXDelta、toYDelta等都是相对当前View的位置。1
2
3
4
5
6
<translate  xmlns:android ="http://schemas.android.com/apk/res/android"  
    android:fromXDelta ="0" 
    android:fromYDelta ="0" 
    android:toXDelta ="500" 
    android:toYDelta ="500" 
    />
1
2
3
4
Animation translateAnimation = AnimationUtils.loadAnimation(MainActivity.this , R.anim.translate);
	translateAnimation.setDuration(5000 );
    view.startAnimation(translateAnimation);
ScaleAnimation 主要有6个属性如下:分别是:起始X轴上的相对自身比例的缩放,比如1是不变2是放大一倍;结束的X方向上相对自身的缩放比例;之后Y轴的类似。pivotX是缩放轴坐标的X坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,当为数值时,表示在当前View的左上角,即原点处加上50px,做为起始缩放点;如果是50%,表示在当前控件的左上角加上自己宽度的50%做为起始点;如果是50%p,那么就是表示在当前的左上角加上父控件宽度的50%做为起始点x轴坐标;pivotY类似
1
2
3
4
5
6
7
8
9
<scale  android:fromXScale ="0"  
    android:toXScale ="1.4" 
    android:fromYScale ="0" 
    android:toYScale ="1.4" 
    android:pivotX ="0" 
    android:pivotY ="0" 
    android:repeatCount ="2" 
    android:duration ="5000" 
    xmlns:android ="http://schemas.android.com/apk/res/android"  />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Animation scaleAnimation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.scale);
                Animation scaleAnimation2 = new ScaleAnimation(0f,1.4f,0f,1.4f,0f,0f);
                view.startAnimation(scaleAnimation);
``` 
##### RotateAnimation
主要有四个属性,如下,分别是:起始的角度,结束的角度,和旋转中心点的坐标,也是对于View的相对坐标
``` xml
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
	android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="0"
    android:pivotY="0"
     />
1
2
3
4
Animation rotateAnimation = AnimationUtils.loadAnimation(MainActivity.this , R.anim.rotate);
                rotateAnimation.setDuration(5000 );
                view.startAnimation(rotateAnimation);
AlphaAnimation 透明动画相对简单一点,主要有fromAlpha和toAlpha,分别为是起始透明度和结束透明度,值是从0.0到1.0,表示全透明到不透明。1
2
3
4
5
6
7
8
9
10
<alpha  xmlns:android ="http://schemas.android.com/apk/res/android"  
    android:fromAlpha ="0" 
    android:toAlpha ="1" 
    android:duration ="5000" 
    />
    
    Animation alphaAnimation = new AlphaAnimation(0f,1f);
                alphaAnimation.setDuration(5000);
                Animation alphaAnimation2 = AnimationUtils.loadAnimation(MainActivity.this, R.anim.alpha);
                view.startAnimation(alphaAnimation);
set 动画合集 set中包含shareInterpolator,表示set中国的动画是否共享一个差值器。同时它还有继承于Animation的属性,如果在set标签下设置了某个属性则对标签内的所有Animation起作用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
	<?xml version="1.0" encoding="utf-8"?>
<set  xmlns:android ="http://schemas.android.com/apk/res/android"  
    android:duration ="5000" 
    android:fillAfter ="true" >
    <alpha  
        android:fromAlpha ="0" 
        android:toAlpha ="1"  />
    <rotate  
        android:fromDegrees ="0" 
        android:pivotX ="0" 
        android:pivotY ="0" 
        android:toDegrees ="360"  />
    <scale  
        android:fromXScale ="0" 
        android:fromYScale ="0" 
        android:pivotX ="0" 
        android:pivotY ="0" 
        android:toXScale ="1.4" 
        android:toYScale ="1.4"  />
    <translate  
        android:fromXDelta ="0" 
        android:fromYDelta ="0" 
        android:toXDelta ="500" 
        android:toYDelta ="500"  />
</set > 
``` 
``` java
Animation scaleAnimation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.set);
view.startAnimation(scaleAnimation);
帧动画 帧动画就是按照顺序播放一些列的图片,实际上是AnimationDrawable。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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/takeout_img_loading_pic1"  android:duration ="84"  /> 
    <item  android:drawable ="@drawable/takeout_img_loading_pic2"  android:duration ="167"  /> 
    <item  android:drawable ="@drawable/takeout_img_loading_pic3"  android:duration ="125"  /> 
    <item  android:drawable ="@drawable/takeout_img_loading_pic4"  android:duration ="42"  /> 
</animation-list > 
``` xml
	<View  
        android:id ="@+id/image_view" 
        android:layout_width ="50dp" 
        android:background ="@drawable/frame" 
        android:layout_height ="50dp"  />
可以将其设置为一个View的background,然后((AnimationDrawable)findViewById(R.id.image_view).getBackground()).start();
View动画的其他场景 View动画除了可以对单个View设置动画效果外也可以设置ViewGoup中子元素的加入效果,也可以设置Activity和Fragment的进入和退出效果
LayoutAnimation LayoutAnimation的属性包括delay:设置动画开始的延迟,比如动画的duration为50ms,delay0.5意味着每个元素都要延迟25ms后进入,第一个元素25ms后进入,第二个元素50ms,以此类推。AnimationOrder是动画的顺序,包括normal顺序进入,random随机,reverse反序.Animation是指定的动画。
需要注意的是LayoutAnimation只在第一次创建的时候才有效,之后向adapter里添加时时无效的。1
2
3
4
5
6
7
8
9
10
11
<layoutAnimation  xmlns:android ="http://schemas.android.com/apk/res/android"  
    android:animation ="@anim/set" 
    android:animationOrder ="normal" 
    android:delay ="0.5" >
</layoutAnimation > 
<ListView  
    android:id ="@+id/listview" 
    android:layout_width ="wrap_content" 
    android:layout_height ="wrap_content" 
    android:layoutAnimation ="@anim/layout" ></ListView > 
LayoutAnimation的java代码实现需要借助LayoutAnimationController
1
2
3
4
5
Animation animation = AnimationUtils.loadAnimation(MainActivity.this , R.anim.set);
LayoutAnimationController controller = new  LayoutAnimationController(animation);
controller.setDelay(0.5f );
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);
同样的GridView也有系统提供的Animation,具体实现为GridLayoutAnimation,不详细介绍。
Activity的Fragemnt的过渡动画 可以通过overridePendingTransition(int enterAnim, int exitAnim)()来为Activity添加进入和退出的动画,第一个参数是第二个Activity的进入动画,第二个参数是第一个Activity的退出动画,需要注意的是:overridePendingTransition(int enterAnim, int exitAnim)()这个方法必须在startActivity之后调用或者在finish()之后调用1
2
3
4
5
6
Intent intent = new  Intent(MainActivity.this , Main2Activity.class);
startActivity(intent);
overridePendingTransition(R.anim.activity_in,R.anim.activty_out);
finish();
overridePendingTransition(android.R.anim.fade_in,android.R.anim.fade_out);
Interpolator 插值器 插值器(Interpolator)是Animation的一个属性,用来设置动画变化过程的,Android自身提供了几种插值器:
AccelerateDecelerateInterpolator   在动画开始与介绍的地方速率改变比较慢,在中间的时候加速 
AccelerateInterpolator                     在动画开始的地方速率改变比较慢,然后开始加速 
AnticipateInterpolator                      开始的时候向后然后向前甩 
AnticipateOvershootInterpolator     开始的时候向后然后向前甩一定值后返回最后的值 
BounceInterpolator                          动画结束的时候弹起 
CycleInterpolator                             动画循环播放特定的次数,速率改变沿着正弦曲线 
DecelerateInterpolator                    在动画开始的地方快然后慢 
LinearInterpolator                            以常量速率改变 
OvershootInterpolator                      向前甩一定值后再回到原来位置 
 
在XML中如下设置:1
2
3
4
5
6
<rotate  xmlns:android ="http://schemas.android.com/apk/res/android"  
    android:toDegrees ="360" 
    android:interpolator ="@android:anim/accelerate_decelerate_interpolator" 
    android:pivotX ="0" 
    android:pivotY ="0" 
    android:fromDegrees ="0"  />
Property Animator 属性动画 属性动画是api11之后引入的,可以实现View动画不实现的功能,比如实现颜色的变化。View动画的作用对象是View,而属性动画可以针对的是对象的属性,属性动画可以通过改变对象的属性来实现动画效果,而View动画是通过其parent view实现的,在View被draw通过改变它的绘制参数,这样虽然View的大小或者旋转改变了,但是View的实际属性并没有变。
属性动画包括:ValueAnimator和ObjectAnimator,其中ObjectAnimator是ValueAnimator的子类。
ValueAnimator ValueAnimator主要是对值进行变化的,不依赖于任何控件,通过对值进行变化然后添加相应的listener。getAnimatedValue()、setRepeatCount()、setRepeatMode()、cancle()1
2
3
4
5
6
7
8
9
10
11
animator = ValueAnimator.ofInt(0 , 500 );
animator.setDuration(3000 );
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.setRepeatCount(1 );
animator.addUpdateListener(new  ValueAnimator.AnimatorUpdateListener() {
    @Override 
    public  void  onAnimationUpdate (ValueAnimator animation)  
        int  curValue = (int )animation.getAnimatedValue();
        view.layout(curValue, curValue, curValue + view.getWidth(), curValue + view.getHeight());
    }
});
同时Animator还可以设置AnimatorLIstener,主要包括:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public  static  interface  AnimatorListener  
    
     * <p>Notifies the start of the animation.</p>
     *
     * @param  animation The started animation.
     */
    void  onAnimationStart (Animator animation) 
    
     * <p>Notifies the end of the animation. This callback is not invoked
     * for animations with repeat count set to INFINITE.</p>
     *
     * @param  animation The animation which reached its end.
     */
    void  onAnimationEnd (Animator animation) 
    
     * <p>Notifies the cancellation of the animation. This callback is not invoked
     * for animations with repeat count set to INFINITE.</p>
     *
     * @param  animation The animation which was canceled.
     */
    void  onAnimationCancel (Animator animation) 
    
     * <p>Notifies the repetition of the animation.</p>
     *
     * @param  animation The animation which was repeated.
     */
    void  onAnimationRepeat (Animator animation) 
}
同时对AnimatorUpdateListener提供了animator.removeAllUpdateListeners();和animator.removeUpdateListener(AnimatorUpdateListener listener)对AnimatorListener也提供了相应的方法RemoveAllListener()和RemoveListener(AnimatorListener listener),当调用RemoveAllListener时也会对PauseListener进行remove操作。
Animator 的其他方法:pause()、resume()和isPause()、isRunning()、setStartDelay()、clone()
自定义插值器(Interpolator) 在Aniamator中也存在插值器,同样是用于设置动画效果的,例如设置运动速率,设置轨迹等。在前面介绍了几种系统内置的插值器,下面自定义自己的插值器:
看下系统的插值器LinearInterpolator:1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  class  LinearInterpolator  implements  Interpolator  
    public  LinearInterpolator ()  
    }
    public  LinearInterpolator (Context context, AttributeSet attrs)  
    }
    public  float  getInterpolation (float  input)  
        return  input;
    }
}
public  interface  Interpolator  extends  TimeInterpolator  
}
它实现了Interpolator接口,而Interpolator没添加其他接口,只是继承了TimeInterpolator,看下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public  interface  TimeInterpolator  
    
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param  input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return  The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float  getInterpolation (float  input) 
}
里面存在一个getInterpolation(float input),这个方法的参数是动画的进度,从0到1,是匀速的不受其他条件变化,只随时间进行进度的变化,输出则是动画的进度值。1
2
3
4
5
6
7
8
9
10
ValueAnimator anim = ValueAnimator.ofInt(100 , 400 );    
anim.setDuration(1000 );    
anim.addUpdateListener(new  ValueAnimator.AnimatorUpdateListener() {    
    @Override     
    public  void  onAnimationUpdate (ValueAnimator animation)  
        float  currentValue = (float ) animation.getAnimatedValue();    
        Log.d("TAG" , "cuurent value is "  + currentValue);    
    }    
});    
anim.start();
getAnimatedValue的值就是 100 + (400 - 100)进度值,进度值 = 动画已持续时间 / 动画总时间 自定义的数值。1
2
3
4
5
6
7
public  class  CustomInterpolator  implements  Interpolator  
    @Override 
    public  float  getInterpolation (float  input)  
        double  x = input * Math.PI / 2 ;
        return   (float ) Math.sin(x);
    }
}
上面实现了在动画时间内完成一个0-90度正弦效果的运动速率。
Evaluator 1
2
3
4
5
6
public  class  IntEvaluator  implements  TypeEvaluator <Integer > 
 public  Integer evaluate (float  fraction, Integer startValue, Integer endValue)  
        int  startInt = startValue;
        return  (int )(startInt + fraction * (endValue - startInt));
    }
}
可以看到这个就是上面提到的公式,最终我们getAnimatedValue得到的值与Evaluator和Interpolator有关
自定义Evaluator
1
2
3
4
5
6
7
public  class  MyEvaluator  implements  TypeEvaluator <Integer > 
    @Override 
    public  Integer evaluate (float  fraction, Integer startValue, Integer endValue)  
        int  startInt = startValue;
        return  (int )(200 +startInt + fraction * (endValue - startInt));
    }
}
上面的操作就在结果上多了200。我们可以调用Animator.setEvaluator()来设置
ArgbEvaluator 通过ArgbEvaluator可以设置颜色的渐变效果1
2
3
4
5
6
7
8
9
10
11
ValueAnimator animator = ValueAnimator.ofInt(0xffffff00 ,0xff0000ff );
animator.setEvaluator(new  ArgbEvaluator());
animator.setDuration(3000 );
animator.addUpdateListener(new  ValueAnimator.AnimatorUpdateListener() {
    @Override 
    public  void  onAnimationUpdate (ValueAnimator animation)  
        int  curValue = (int )animation.getAnimatedValue();
        view.setBackgroundColor(curValue);
    }
});
animator.start();
ArgbEvaluator的源码的原理和上面的原理相似,也是在startValue上加上当前进度 * (endValue - startValue)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public  class  ArgbEvaluator  implements  TypeEvaluator  
    public  Object evaluate (float  fraction, Object startValue, Object endValue)  
        int  startInt = (Integer) startValue;
        int  startA = (startInt >> 24 );
        int  startR = (startInt >> 16 ) & 0xff ;
        int  startG = (startInt >> 8 ) & 0xff ;
        int  startB = startInt & 0xff ;
        int  endInt = (Integer) endValue;
        int  endA = (endInt >> 24 );
        int  endR = (endInt >> 16 ) & 0xff ;
        int  endG = (endInt >> 8 ) & 0xff ;
        int  endB = endInt & 0xff ;
        return  (int )((startA + (int )(fraction * (endA - startA))) << 24 ) |
                (int )((startR + (int )(fraction * (endR - startR))) << 16 ) |
                (int )((startG + (int )(fraction * (endG - startG))) << 8 ) |
                (int )((startB + (int )(fraction * (endB - startB))));
    }
}
ObjectAnimator 我们可以看到ValueAnimator是通过改变数值,然后通过添加Listener,然后在回调中设置View的属性变化。为了简化整个流程,google推出了ObjectAnimator,其实ValueAnimator的子类,所以Valuemator有的方法,它都有。但它主要是通过反射获取到相应的属性的set方法,然后设置值。因此它的操作更加简单,如果参数或者属性错误则不会产生动画。
1
2
3
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotation" , 0 , 180  ,0 );
animator.setDuration(2000 );
animator.start();
View方法主要有以下几类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  void  setAlpha (float  alpha) 
public  void  setRotation (float  rotation) 
public  void  setRotationX (float  rotationX) 
public  void  setRotationY (float  rotationY) 
public  void  setTranslationX (float  translationX)  
public  void  setTranslationY (float  translationY) 
public  void  setScaleX (float  scaleX) 
public  void  setScaleY (float  scaleY) 
对比
因为原理是通过将设置的属性的第一个字母大写,然后添加set,找到该方法,然后设置值来产生动画。所以可以自定义一个属性来根据这个属性生成动画。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public  class  CircleView  extends  View  
    public  CircleView (Context context)  
        super (context);
    }
    public  CircleView (Context context, AttributeSet attrs)  
        super (context, attrs);
    }
    public  CircleView (Context context, AttributeSet attrs, int  defStyleAttr)  
        super (context, attrs, defStyleAttr);
    }
    int  r = 100 ;
    @Override 
    protected  void  onDraw (Canvas canvas)  
        super .onDraw(canvas);
        Paint paint = new  Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(300 , 300 , r, paint);
    }
    public  void  setRadius (int  radius)  
        r = radius;
        invalidate();
    }
}
 ObjectAnimator animator = ObjectAnimator.ofInt(view2, "radius" , 0 , 200  ,100 );
 animator.setDuration(2000 );
 animator.start();
效果如下