在开发项目的过程中几乎都会使用自定义控件,无论是组合型的或者画出来的。而要想使自定义控件满足我们所希望的各种效果,就必须得掌握动画的使用,今天就来总结一下如何使用。

在Android动画中,总共有两种类型的动画

1.View Animation(视图动画): View Animation:Tween Animation(补间动画)和Frame Animation(逐帧动画); 
 2.Property Animator(属性动画);:ValueAnimator和ObjectAnimator

区别:

1.View动画只是实现了一种视觉上的动画效果,其本身的在屏幕上的位置等属性是不会变化的。属性动画是通过改变控件的属性来实现的一种动画效果。

2.属性动画是3.0之后出来的,它可以实现View动画实现不了的功能比如渐变色等。

一:View动画使用

1.translate:平移动画

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fillAfter="true"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toXDelta="200"
    android:toYDelta="200">
</translate>
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate1);
textView1.startAnimation(animation);

代码写法:

//TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
TranslateAnimation animation1=new TranslateAnimation(0,200,0,200);
animation1.setDuration(2000);
animation1.setFillAfter(true);
animation1.setRepeatCount( 10000);
animation1.setRepeatMode(Animation.REVERSE);
textView1.startAnimation(animation1);

2.rotate:旋转动画

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0.0"
    android:toDegrees="620.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="700"
    android:fillAfter="true"
    android:repeatCount="3"
    android:repeatMode="reverse"
    >

</rotate>
Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate1);
textView1.startAnimation(animation);

代码写法:

RotateAnimation animation1=new RotateAnimation(0.0f,620.0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation1.setDuration(1000);
animation1.setRepeatCount(3);
animation1.setFillAfter(true);
animation1.setRepeatMode(Animation.REVERSE);
textView1.startAnimation(animation1);

3.scale:缩放动画

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXScale="0.0"
    android:toXScale="1.2"
    android:fromYScale="0.0"
    android:toYScale="1.2"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="700"
    android:fillBefore="true"
    android:repeatCount="3"
    android:repeatMode="restart"
    >
</scale>
Animation animation = AnimationUtils.loadAnimation(this, R.anim.scale1);
textView1.startAnimation(animation);

代码写法:

//ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY)
//ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

ScaleAnimation animation1=new ScaleAnimation(0.0f,1.0f,0f,1.0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation1.setDuration(3000);
animation1.setFillBefore(true);
animation1.setRepeatCount(3);
animation1.setRepeatMode(Animation.RESTART);
textView1.startAnimation(animation1);

alpha:透明度动画

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="0.0"
    android:toAlpha="1.0"
    android:duration="2000"
    android:fillBefore="true"
    android:repeatCount="3"
    android:repeatMode="restart"
    >
</alpha>
//0.0 全透明  1.0不透明
Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha1);
textView1.startAnimation(animation);

代码写法:

// AlphaAnimation(float fromAlpha, float toAlpha)
 AlphaAnimation animation1=new AlphaAnimation(0.0f,1.0f);
 animation1.setDuration(3000);
 animation1.setFillBefore(true);
 animation1.setRepeatCount(3);
 animation1.setRepeatMode(Animation.RESTART);
 textView1.startAnimation(animation1);

5.set集合动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fillAfter="true">

    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0"/>

    <scale
        android:fromXScale="0.0"
        android:toXScale="1.2"
        android:fromYScale="0.0"
        android:toYScale="1.2"
        android:pivotX="50%"
        android:pivotY="50%"/>

    <rotate
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"/>

</set>
Animation animation = AnimationUtils.loadAnimation(this, R.anim.allanimation);
textView1.startAnimation(animation);

代码写法:

AlphaAnimation  alphaAnim = new AlphaAnimation(0.1f,1.0f);
ScaleAnimation scaleAnim = new ScaleAnimation(0.0f,1.2f,0.0f,1.2f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
RotateAnimation rotateAnim = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);

AnimationSet setAnim=new AnimationSet(true);
setAnim.addAnimation(alphaAnim);
setAnim.addAnimation(scaleAnim);
setAnim.addAnimation(rotateAnim);
setAnim.setDuration(3000);
setAnim.setFillAfter(true);
textView1.startAnimation(setAnim);

二:属性动画(ValueAnimator和ObjectAnimator)

1.核心方法:

ValueAnimator ofInt(int... values)
ValueAnimator ofFloat(float... values)
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int animatedValue = (int) animation.getAnimatedValue();
    }
});
//        ValueAnimator animator=ValueAnimator.ofFloat(0f,0.2f,0.4f,0.8f,1.0f);
        ValueAnimator animator=ValueAnimator.ofInt(0,360);
        animator.setDuration(9000);
        animator.setRepeatCount(20);
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.start();
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int animatedValue = (int) animation.getAnimatedValue();
//                textView1.setTextScaleX(animatedValue);
//                textView1.setAlpha(animatedValue);
//                textView1.setScaleX(animatedValue);
//                textView1.setScaleX(animatedValue);
                textView1.setRotation(animatedValue);
                Log.e("TAG",animatedValue+"");
                //刷新布局
                textView1.requestLayout();
            }
        });

说明:在不设置差值器情况下 如果设置A->B 则是匀速的 ,如果设置多个数值,他是根据这个规律的。

           这种属性动画不是直接对View进行动画操作,而是对一组数据进行操作处理,然后在addUpdateListener拿到这种值并对            View进行属性操作。

原理:首先设置动画参数ofInt,ofFloat---->获取Interceptor系数-->计算出Evaluater的值-->addUpdateListener中获取该值。最后手动操作设置属性。

2.自定义Interpolator 和自定义Evalutor  

public class MyIntercepter implements Interpolator {

    @Override
    public float getInterpolation(float input) {
        return input*3;
    }
}
public class MyEvaluate implements TypeEvaluator<Integer>{

    @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
       int start=startValue;
       int end=endValue;
       int cuur= (int) (start+fraction*(end=start));
        return cuur;
    }
}
animation1.setInterpolator(new MyIntercepter());

对于ValueAnimator中的addUpdateListener回调中获取的值animation.getAnimatedValue(); 就是cuur。 我们可以通过自定义Evaluate来修改获取的实时的值。 fraction这个系数是什么呢? 他就是MyIntercepter差值器的getInterceptor的返回值,input是0--1的值代表着时间进度情况,只与时间有关。我们根据要求计算出对应的数学函数作为返回值,这样就改变了动画的速率,或者说 改变了cuur的系数,从而达到动画效果。比如前半段时间运动快后半段时间运动慢等操作。  例如:

public class MyIntercepter1 implements Interpolator {

    @Override
    public float getInterpolation(float input) {
        if (input<=0.5){
            input= (float) (input*1.5);
        }else if (input>0.5){
            input= (float) (0.5+input*0.5);
        }
        return input*3;
    }
}
public class MyEvaluate1 implements TypeEvaluator<MyPoint>{
    @Override
    public MyPoint evaluate(float fraction, MyPoint startValue, MyPoint endValue) {

        int start=startValue.getRadio();
       int end=endValue.getRadio();
       int cuur= (int) (start+fraction*(end-start));
        return new MyPoint(cuur);
    }
}

ValueAnimator ofObject(TypeEvaluator evaluator, Object... values);

ValueAnimator animator=ValueAnimator.ofObject(new MyEvaluate1(),
            new MyPoint(5),new MyPoint(20));
    animator.setDuration(9000);
    animator.setRepeatCount(20);
    animator.setRepeatMode(ValueAnimator.RESTART);
    animator.start();
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            MyPoint animatedValue = (MyPoint) animation.getAnimatedValue();
            Log.e("TAG",animatedValue+"");
            //刷新布局
            textView1.requestLayout();
        }
    });

}

颜色变化:

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();
            tv.setBackgroundColor(curValue);

        }
    });
 
animator.start();

一般情况 不需要自义。系统提供的一般可以满足。特殊情况 还得通过数学计算得到一个函数,让动画的相关参数的返回值按照计算返回,达到想要的动画的目的。

3.ObjectAnimator 属性动画 :与上一个动画不同的是,这个属性动画是对View进行属性操作,从而达到动画效果。

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)
第一个参数动画要操作的是哪个控件
第二个参数动画要操作这个控件的哪个属性
第三个参数是可变长参数,指这个属性值是从哪变到哪

原理:首先设置动画参数ofInt,ofFloat---->获取Interceptor系数-->计算出Evaluater的值,然后通过反射将值set到被操作控件的属性方法中。    根据原理可以看到想要修改某个控件的属性就必须要有该属性的setProper方法,并且要遵循驼式命名法,使用的时候是将"set"去掉,并首字母小写。例如:

public void setTranslationX(float translationX)
ObjectAnimator animator=ObjectAnimator.ofFloat(textView1,"translationX",50,200);

 //1. 平移:translationX、translationY
public void setTranslationX(float translationX);
public void setTranslationY(float translationY);

//2. 缩放:scaleX、scaleY
public void setScaleX(float scaleX);
public void setScaleY(float scaleY);

//3.旋转度数:rotation、rotationX、rotationY
public void setRotation(float rotation);
public void setRotationX(float rotationX);
public void setRotationY(float rotationY);

//4.透明度:alpha
public void setAlpha(float alpha);

自动义属性:只要掌握其原理就行,只是在View里面加一些set属性的方法就行,再是用的时候和上面的一样用,就是如此简单。另外也可以设置getProperty方法,此方法是当ofInt  odFloat  的属性值参数只有一个的时候,就默认把传进来的当做结束值,把getProperty的值作为起始值。

组合动画:

ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(textView1, "translationY", 0, 300, 0);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(textView2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
//按顺序
animatorSet.playSequentially(tv1TranslateY,tv2TranslateY);
//同时播放
animatorSet.playTogether(tv1TranslateY,tv2TranslateY);
animatorSet.setDuration(1000);
animatorSet.start();
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(textView1, "translationY", 0, 400, 0);
ObjectAnimator tv1Alpha = ObjectAnimator.ofFloat(textView1, "alpha", 0.1f, 1.0f);
ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(textView2, "translationY", 0, 500, 0);
ObjectAnimator tv2Alpha = ObjectAnimator.ofFloat(textView2, "alpha", 0.1f, 1.0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv1TranslateY).before(tv2Alpha).with(tv2TranslateY).after(tv1Alpha);
animatorSet.setDuration(1000);
animatorSet.start();

监听方法:

animatorSet.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
        Log.e("TAG", "animator start");
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        Log.e("TAG", "animator end");
    }

    @Override
    public void onAnimationCancel(Animator animation) {
        Log.e("TAG", "animator cancel");
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
        Log.e("TAG", "animator repeat");
    }
});

上面的一些使用法发比较简单 基本看看代码就能理解。动画这块内容还是不少的,但是理解了  还是很好记忆的。有什么不对的 还望不吝指教啊 。