参考了:http://blog.csdn.net/kkkding/article/details/8653395
http://blog.csdn.net/jdsjlzx/article/details/45558901自己加以整理。
android的三种动画:
1.Tween Animation:补间动画(包括透明度alpha、平移translate、旋转ratate、缩放scale)。
2.Frame Animation:帧动画(一帧帧播放)
3.Property Animation:属性动画
一、补间动画
给出两个关键帧,通过一些算法将给定属性值在给定的时间内在两个关键帧间渐变。
补间动画只是改变view绘制的位置,不改变view本身。比如view触发动画的位置还是原位置。
在XML中定义:
动画的XML文件在工程中res/anim目录。
rotate、alpha、translate、scale、set都可以做根元素、其中set表示多个动画的集合。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true" //表示动画结束后停在最后的位置,fillBefore表示动画结束后停在开始的位置
android:zAdjustment="normal"> //调整z轴的次序,normal保持当前的z轴次序,top在最上层显示,buttom在下层显示。
<rotate
android:startOffset="1000" //开始动画的时间偏移,可以用这个参数控制不同动画的播放次序。
android:fromDegrees="0" //开始角度
android:toDegrees="360" //结束角度
android:pivotX="50%" //中心点x坐标
android:pivotY="50%" //中心点y坐标
android:duration="4000" //动画持续时间
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
/>
<translate
android:fromXDelta="0"
android:toXDelta="1000"
/>
<scale
android:fromXScale="0.5"
android:toXScale="1.0"
android:pivotX="50%"/>
<alpha
android:fromAlpha="0"
android:toAlpha="1"
/>
</set>
调用:
Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.rotate);
//监听动画的状态(开始,结束)
anim.setAnimationListener(new EffectAnimationListener());
textWidget = (TextView)findViewById(R.id.text_widget);
textWidget.startAnimation(anim);
二、帧动画
帧动画定义在drawable目录下。】
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true" //true只播放一次
android:variablePadding="true" //true表示图片的padding随图片变化
>
<item android:drawable="@drawable/p1" android:duration="1000"></item>
<item android:drawable="@drawable/p2" android:duration="1000"></item>
<item android:drawable="@drawable/p3" android:duration="1000"></item>
</animation-list>
调用:
不要在onCreate中调用start,因为AnimationDrawable还没有完全跟Window相关联,如果想要界面显示时就开始动画的话,可以在onWindowFoucsChanged()中调用start()。
AnimationDrawable anim = (AnimationDrawable)getResources().
getDrawable(R.drawable.frame);
textWidget = (TextView)findViewById(R.id.text_widget);
textWidget.setBackgroundDrawable(anim);
anim.start();
三、属性动画
属性动画与补间动画不同,属性动画改变了视图的实际属性,如尺寸、颜色等。
ValueAnimator类用来计算在动画过程中,视图的各个属性的值。
计算的流程是这样的:
1、TimeInterpolation用来定义属性变化的速率,比如你想让一点从的横坐标逐渐变大,TimeInterpolation可以定义横坐标均匀变化,还是加速地变化,还是函数关系的变化。
2、TimeInterpolation会给TypeEvaluator传递一个时间因子,然后TypeValue根据传递的时间因子、属性的初始值、属性的结束值计算出该属性这个时刻的值。
举个栗子,默认的动画重绘时间间隔是10ms,我设定的动画是1秒钟内,X坐标从0变到500。如果TimeInterpolation设置的是均匀变化,那么第一次重绘时TimeInterpolation计算的时间因子是10/1000,=0.01,也就是说10ms内X坐标要变化1%,那么TypeEvaluator计算的属性值是0.01*(500-0);当TimeInterpolation设置是其他变化方式时,TimeInterpolation根据函数关系计算每次重绘该属性改变的百分比,TypeEvaluator的计算方式不变。
3.知道了属性,就可以重绘了。
在这里自定义了一个更改自身透明度的TextView
public class MyTextView extends TextView{
private float alpha;
private Paint mPaint;
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d("MyTextView", "Constructor");
mPaint=new Paint();
mPaint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
Log.d("MyTextView", "draw");
mPaint.setAlpha(alpha);
canvas.drawCircle(500, 500, 100, mPaint);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
Log.d("MyTextView", "onWindowFocusChanged");
super.onWindowFocusChanged(hasWindowFocus);
startAnimation(); //在这里调用start的原因上面已经说过
}
private void startAnimation(){
Log.d("MyTextView", "startAnimation");
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);//变化的属性(透明度)值的类型是float,从0变到1,还有ofInt,ofObject,后面在举例子。
animation.setDuration(1000);
animation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
alpha=(float)valueAnimator.getAnimatedValue(); //在每次重绘之前,你能得到变化的属性值。
invalidate(); //重绘
}
});
animation.setInterpolator(new CycleInterpolator(3));
animation.start();
}
这样这个TextView就能动起来了。
上面说到的ofObject是怎么回事呢?上面的例子ofFloat定义的是一个float型的属性的渐变,ofObject可以自定义任何类型的属性渐变。比如下面我们自定义一个坐标Point的渐变。
定义一个point类
public class Point {
private int x,y;
public Point(int x,int y){
this.x=x;
this.y=y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
这里最重要的一点,需要重写TypeEvaluator,因为对于我们自定义的属性,TypeEvaluator无法根据时间因子计算出属性值。
public class PointEvaluate implements TypeEvaluator {
@Override
public Object evaluate(float v, Object o, Object t1) {//v是时间因子,o是初始属性值,t1是结束属性值
Point startPoint=(Point)o;
Point endPoint=(Point)t1;
int x=(int)(startPoint.getX()+v*(endPoint.getX()-startPoint.getX()));
int y=(int)(startPoint.getY()+v*(endPoint.getY()-startPoint.getY()));
return new Point(x,y);
}
}
修改一下自定义的TextView
public class MyTextView extends TextView{
private Point currPoint;
private Paint mPaint;
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d("MyTextView", "Constructor");
mPaint=new Paint();
mPaint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
Log.d("MyTextView", "draw");
if(currPoint==null){
currPoint=new Point(50,50);
}
canvas.drawCircle(currPoint.getX(), currPoint.getY(), 100, mPaint);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
Log.d("MyTextView", "onWindowFocusChanged");
super.onWindowFocusChanged(hasWindowFocus);
startAnimation();
}
private void startAnimation(){
Log.d("MyTextView", "startAnimation");
ValueAnimator animator= ValueAnimator.ofObject(new PointEvaluate(), new Point(50, 50), new Point(1000, 1000));//这句代码是重点,我们指定了TypeEvaluator
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
currPoint=(Point)valueAnimator.getAnimatedValue();//得到变化后的point的值
invalidate();//重绘
}
});
animator.setDuration(5000);
animator.start();
}
}
通过上面的例子比较容易理解属性动画的过程。如果是简单的动画,可以通过继承自ValueAnimaton的ObjectAnimation完成。
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);//参数一:表示动画的对象;参数二表示属性名,参数三和四表示变化范围
oa.setDuration(3000);
oa.addListener(new AnimatorListenerAdapter(){
public void on AnimationEnd(Animator animation){
Log.i("Animation","end");
}
});
oa.start();