Android动画共分为两种:View Animation(视图动画)和Property Animator(属性动画)
- View Animation 包括 Tween Animation(补间动画)和 Frame Animation(逐帧动画)
- Property Animator 包括 ValueAnimator 和 ObjectAnimation
View Animation 和 Property Animator的区别:
区别 | View Animation | Property Animator |
---|---|---|
引入时间 | API Level 1 | API Level 11 |
所在包名 | android.view.animation | android.animation |
命名 | XXXXAnimation | XXXXAnimator |
作用对象 | 控件 | 控件属性 |
这里以TranslateAnimation位移动画为例,补间动画改变的只是控件的显示位置,没有改变控件的实际位置。这个过程是由Parent View来实现的,在View被绘制时,Parent View改变View的 绘制参数,这个View就会发生对应的位移动画,但是View的实际参数并没有改变。对应的View在移动过程中和移动后是没有点击效果的,然而在View原来的点击区域,可能此时已经不可见,但是仍然可以有点击效果。属性动画就恰恰相反,属性动画是通过改变控件的内部属性值来实现动画效果。
简单使用:
valueAnimator = ValueAnimator.ofInt(10,800);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
tv.setText("值:"+value);
img.layout((int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,16,getResources().getDisplayMetrics())+value), (int) img.getY(),
(int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,16,getResources().getDisplayMetrics())+value+img.getWidth()),(int) img.getY()+img.getHeight());//坐标以父控件为基准
}
});
valueAnimator.setDuration(1000);
valueAnimator.start();
基本的的api使用,请查看api文档,这里我们将一些别的。
取消监听的方法
/*
* 移除 AnimatorUpdateListener
*/
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
/*
* 移除 AnimatorListener
*/
void removeListener(AnimatorListener listener);
void removeAllListeners();
/*
* 延时多久时间开始,单位是毫秒
*/
public void setStartDelay(long startDelay)
/*
* 完全克隆一个 ValueAnimator 实例,包括它所有的设置以及所有对监听器代码的处理
* 就像克隆羊一样,克隆羊拥有母体所有的特征,但是完成克隆之后,就是新的生命体,跟母体也就没有任何关系了
*/
public ValueAnimator clone()
Evaluator计算器
Evaluator其实就是一个转换器,将小数进度转换成对应的数值。Evaluator都是专用的,比如ofInt(int...),那么对应的Evaluator必然要返回int类型的值,否则就会报强转的错误。valueAnimator.setEvaluator()来设置转换器.
IntEvaluator源码:
public class IntEvaluator implements TypeEvaluator {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
其中 fraction 就是插值器中的返回值,表示当前动画的数值进度,百分制的小数表示。 startValue 和 endValue 分别对应 ofInt(int start,int end)中的 start 和 end 的数值;
自定义Evaluator
public class MyEvaluator implements TypeEvaluator {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(200+startInt + fraction * (endValue - startInt));
}
}
所以我们可以通过自定义插值器改变数值进度来改变数值位置,也可以通过自定义Evaluator改变进度所对应数值来改变数值位置。
ArgbEvaluator色值过渡计算器
例子:
valueAnimator = ValueAnimator.ofInt(0xfff10f0f,0xfff10fbf,0xff740ff1,0xff2f0ff1,0xff0f94f1,0xff0ff1af,0xff14f10f,0xffeaf804,0xfff92a0f);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
img.setBackgroundColor(value);
}
});
valueAnimator.setDuration(6000);
valueAnimator.setEvaluator(new ArgbEvaluator());
valueAnimator.start();
效果:
源码:
public class ArgbEvaluator implements TypeEvaluator {
private static final ArgbEvaluator sInstance = new ArgbEvaluator();
/**
* @hide
*/
public static ArgbEvaluator getInstance() {
return sInstance;
}
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
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))));
}
色值:A R G B ,分别表示透明度,红色,绿色,蓝色,每一个色值都用十六进制来表示,0xffff0000,
色值是通过位移和运算求出的。色值和ARGB对应关系如下:
ofObject讲解
ofObject()可以实现自定义类型的动画效果
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values);
第一个是自定义的 Evaluator,第二个是可变长参数,Object 类型的
一个小例子:
自定义Evaluator
public class MyEvaluator implements TypeEvaluator {
private static final String TAG = "MyEvaluator";
@Override
public String evaluate(float fraction, String startValue, String endValue) {
int length = endValue.length();
String result = String.valueOf(endValue.charAt((int) (fraction * (length -1))));
return result;
}
}
ValueAnimator animator = ValueAnimator.ofObject(new MyEvaluator(),"且品鸡汤莫问厨娘");
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
String str = (String) animation.getAnimatedValue();
tv.setText(str);
}
});
animator.setDuration(5000);
animator.setInterpolator(new LinearInterpolator());
animator.start();
自定义对象实例
效果图:
private void animatorOfObjectCustom(){
ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(),new Ponit(20),new Ponit(200));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Ponit ponit = (Ponit) animation.getAnimatedValue();
mCircleView.setPoint(ponit);
}
});
animator.setDuration(1000);
animator.setInterpolator(new BounceInterpolator());
animator.start();
}
自定义类
public class Ponit {
private int mRadius;
public Ponit() {
}
public Ponit(int mRadius) {
this.mRadius = mRadius;
}
public int getRadius() {
return mRadius;
}
public void setRadius(int mRadius) {
this.mRadius = mRadius;
}
}
自定义view
public class CircleView extends View {
private Ponit mCurrentPoint;
private Paint mPiant ;
private int mScreenWidth;//屏幕宽度
public CircleView(Context context) {
this(context,null);
}
public CircleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPiant = new Paint(Paint.ANTI_ALIAS_FLAG);
mPiant.setColor(Color.RED);
mPiant.setStyle(Paint.Style.FILL);
mScreenWidth = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
}
@Override
protected void onDraw(Canvas canvas) {
if (mCurrentPoint != null){
canvas.drawCircle(mScreenWidth/2,getY()+getPaddingTop(),mCurrentPoint.getRadius(),mPiant);
}
}
public void setPoint(Ponit point){
this.mCurrentPoint = point;
invalidate();
}
}