属性动画的分类
ValueAnimator
ValueAnimator是整个属性动画机制当中最核心的一个类,它通过我们给定的初始值,结束值和动画时间,内部计算出动画过程,从而完成平滑的移动效果。另外,它还管理动画的播放次数,模式以及设置监听等功能。
它是最基础的核心类,并不能直接操作View,他操作的是值,操作的对象通常也是对值进行包装的对象。但是,我们可以根据这些值的变化来实现View的动画效果。
常用方法:
ValueAnimator.ofFloat/ofint 设置初始值和结束值 ,可以传入多个参数,运行时依次变化到最后一个值
setDuration() 设置动画时间
addUpdateListener 为动画设置监听,可以随时获取动画的当前状态
setStartDelay() 设置动画延时
setRepeatCount()/Mode() 设置重复次数,重复模式(RESTART,REVERSE)
ValueAnimator实现动画效果
除了上边的方法之外,ValueAnimator还有一个稍微复杂的ofObject()方法,用来操作对象,可以用它来实现视图的动画效果。它接收三个参数,除了初始值和结束值之外,它还需要一个TypeEvaluator。
TypeEvaluator是一个用来计算滑动过程的接口,查看一下ofFloat/ofint,他们内部也实现了这个接口,我们操作对象的时候,需要自己定义计算方法,他有三个参数,第一个表示完成度,后两个表示初始和结束值。
下面用一个例子来演示一下ValueAnimator是如何操作View的。
首先定义一个class,用来存储Value(x,y方法的坐标值),View的移动通过改变坐标来实现。
public class Cordinate {
private float x;
private float y;
public Cordinate(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
然后自定义一个View,用来实现一个圆形的移动效果:
public class ValueAnimatorDemoView extends View{
private Paint mPaint;
private Cordinate curCordinate;
public ValueAnimatorDemoView(Context context) {
this(context,null);
// TODO Auto-generated constructor stub
}
public ValueAnimatorDemoView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
mPaint = new Paint();
mPaint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
if (curCordinate == null) {
curCordinate = new Cordinate(50 , 50);
drawCircle(canvas);
startAnimation();
} else {
drawCircle(canvas);
}
}
private void drawCircle(Canvas canvas) {
float x = curCordinate.getX();
float y = curCordinate.getY();
canvas.drawCircle(x, y, 50, mPaint);
}
private void startAnimation() {
Cordinate startPoint = new Cordinate(50, 50);
Cordinate endPoint = new Cordinate(getWidth() - 50, getHeight() - 50);
ValueAnimator anim = ValueAnimator.ofObject(new MyEvalutor(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
curCordinate = (Cordinate) animation.getAnimatedValue();
invalidate();
}
});
anim.setDuration(5000);
anim.start();
}
private class MyEvalutor implements TypeEvaluator<Cordinate>{
@Override
public Cordinate evaluate(float fraction, Cordinate startValue,
Cordinate endValue) {
// TODO Auto-generated method stub
Cordinate startPoint = (Cordinate) startValue;
Cordinate endPoint = (Cordinate) endValue;
float x = startPoint.getX() + fraction*(endPoint.getX() -startPoint.getX() );
float y = startPoint.getY() + fraction*(endPoint.getY() -startPoint.getY() );
Cordinate curpoint = new Cordinate(x,y);
return curpoint;
}
}
}
在onDraw方法中,先进行判断,如果curCordinate对象为null,说明是第一次运行,新建一个坐标Cordinate对象,初始值为50,50,用来在屏幕的X/Y坐标为50,50的地方(左上角),绘制一个圆形,半径为50。
绘制完成后,开始动画,第一步定义初始和结束位置,分别是左上角和右下角,然后开始运行动画。需要注意的是这里添加了UpdateListener用来实时监听当前坐标值,然后invalidate,根据当前坐标绘制圆形,而当前坐标又是通过MyEvalutor 方法来计算出的,是一系列逐步变化的值,通过这些值来绘制View就完成了整个动画效果。
ObjectAnimator
ObjectAnimator继承自ValueAnimator,它可以对View的各项属性进行操作。
例如将一个View从常规变换成全透明,再从全透明变换成常规,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
再看一个变化背景颜色的例子:
ValueAnimator colorAnim = ObjectAnimator.ofInt(mButton,"backgroundColor", 0xFFFF8080, 0xFF8080FF);
colorAnim.setDuration(5000);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.start();
这里用来系统的ArgbEvaluator来进行颜色变化的计算,当然我们也可以自己定义变化方法。另外需要注意的是第二个属性,它的原理是查找所操作的对象中对应的setXXX和getXXX方法,XXX就是我们填入的参数。常用的参数有这些:
rotation, rotationX/Y, translationX/Y, scaleX/Y, alpha,color, backgroundColor等等
除此之外,我们也可以自己来定义参数,但是要注意,自定义的参数一定要有setXXX和getXXX方法,并且在这两个方法中,实现对动画所操作对象的属性设置。
AnimatorSet
AnimatorSet是一系列动画的集合,也可以叫组合动画。
例如:
AnimatorSet animSet = new AnimatorSet();
animSet.playTogether(
ObjectAnimator.ofFloat(mButton, "translationX", -500f, 0f),
ObjectAnimator.ofFloat(mButton, "rotation", 0f, 360f),
ObjectAnimator.ofFloat(mButton, "alpha", 1f, 0f, 1f));
AnimatorSet 提供了一个play方法,返回的是一个AnimatorSet.Builder对象,可以进行以下操作:
after(Animator anim) 将现有动画插入到传入的动画之后执行
after(long delay) 将现有动画延迟指定毫秒后执行
before(Animator anim) 将现有动画插入到传入的动画之前执行
with(Animator anim) 将现有动画和传入的动画同时执行
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();
以上代码表示旋转和淡入淡出动画同时进行,并把它们插入到了平移动画的后面。
XML动画
XML动画是将属性动画的各项属性在XML中进行设置,功能与代码中设置是一样的,它最大的好处是可以重复引用。
使用XML动画时,首先在res下新建一个animator文件夹,所有的属性动画XML都放在该文件夹下。设置属性动画有以下几个标签:
<animator>: ValueAnimator
<objectAnimator>: ObjectAnimator
<set>: AnimatorSet
示例如下:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially" >
<Animator
android:duration="2000"
android:valueFrom="-500"
android:valueTo="0"
android:valueType="floatType" >
</Animator>
<set android:ordering="together" >
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType"
android:startOffset="5"
android:repeatCount="2"
android:repeatMode="restart">
</objectAnimator>
<set android:ordering="sequentially" >
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" >
</objectAnimator>
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" >
</objectAnimator>
</set>
</set>
</set>
属性简介:
android:ordering 动画的执行顺序,默认为together,表示各个动画同时执行。sequentially表示顺序执行。
android:propertyName 动画的动作类型,alpha,color,translateX等
android:valueType 属性类型,有intType和floatType两个选项
android:valueFrom/To 初始值和结束值
android:startOffset 动画开始之后,延迟多少时间开始执行
XML使用方法如下:
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
//AnimatorSet set = (AnimatorSet ) AnimatorInflater.loadAnimator(context, R.animator.anim_xml);
animator.setTarget(view);
animator.start();
Animator监听
Animator类中为我们提供了一个addListener(),它接收一个AnimatorListener作为参数,可以实现对动画开始,结束,重复和取消的监听:
anim.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
如果只需要对某个事件监听,可以用AnimatorListenerAdapter(),它已经内部实现了Listener中的方法,我们可以根据需要覆写自己需要的方法即可
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});
Interpolator和Evaluator
这两个东西翻译过来可以叫做差值器和估值器。从补间动画开始就支持Interpolator接口了,在属性动画中新增了一个TimeInterpolator接口,它有几种常用实现:
LinearInterpolator:线性差值器,适用于匀速动画
AccelerateInterpolator:加速差值器,运行速度越来越快
DecelerateInterpolator,减速差值器,运行速度越来越慢
AccelerateDecelerateInterpolator:加减速差值器,动画运行时中间速度快,两头速度慢
BounceInterpolator:弹性差值器,模拟弹跳动作。
属性动画默认使用的就是AccelerateDecelerateInterpolator,需要改变差值器设置的时候,调用Animator对象的setInterpolator方法就可以了,参数2f就是我们设置的加速度。:
anim.setInterpolator(new AccelerateInterpolator(2f));
anim.setInterpolator(new BounceInterpolator());
那么,Interpolator的作用原理是怎样的呢?看一下TimeInterpolator接口的代码:
public interface TimeInterpolator {
float getInterpolation(float input);
}
很简单,只是根据input的值来返回一个float数。这里,input是一个从0到1的变化值,在动画的运行过程中,input会从随时间流逝从0匀速变化为1。Interpolator 要做的,就是根据input,通过计算之后,返回我们需要的数值。比如LinearInterpolator,线性差值器,它也是匀速的,所以它什么都没有做,直接在getInterpolation方法中返回了input。
理解了Interpolation之后,还需要介绍一个Evaluator的概念,在上文的例子中我们用到了一个自定义的TypeEvaluator,MyEvaluator,它的作用根据fraction计算当前坐标,封装到Cordinate对象里返回,然后View根据这个坐标来绘制圆形。看到这里,TypeEvaluator的作用就很清楚了,估值器决定了动画在某一个时刻的具体状态。
fraction,这个参数就是我们通过Interpolator中的getInterpolation得到的。也就是说,Interpolator决定了动画的整体变化规律,Evaluator根据这个规律,来实现具体某一时刻的状态。
在上文的例子中,我们是根据fraction来计算圆形的坐标位置,如果是颜色,那么就需要根据fraction来计算颜色的变化并返回封装好的颜色值。Interpolator和Evaluator一起决定了动画的最终表现形式。
ViewPropertyAnimator
ViewPropertyAnimator是专门为View开发的一个辅助类,用起来非常简单,直接调用View对象的.animate()方法,得到一个ViewPropertyAnimator对象,就可以进行动画了
textview.animate().x(500).y(500).setDuration(5000) .setInterpolator(new BounceInterpolator());
表示在5s内将textView移动到500,500,动画效果是弹跳。
网友评论