android动画 属性动画详解

参考了: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();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值