前言:
安卓里面由于补间动画,只是变化的是视图的内容,但是属性的话,是没有变的,就是以前大家在使用动画的时候,如果在tagView(目标视图)上设置了监听事件,但是,当tagView在移动的时候,点击事件还在原位置,这样很不方便,后面在API3.0以后就新增了属性动画,很好的解决了以上问题,而且新增的功能还可以扩展很多的动画效果,下面就先来说说ValueAnimator的重要性
分析:
动画,简单来说就是在一段时间里面进行一系列视图的变化,也就是必须有一定的过程,在数学里面也是就时间段,而不是时间刻,(小装个逼,嘻嘻!)
一、ValueAnimator(非常重要的):
1.首先ValueAnimator继承于父类的Animator,而它的实现子类ObjectAnimator以及TimeAnimator,暂时这里先不说这两个子类
2.学习新的类,肯定要先了解其API的使用:
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 1);
valueAnimator.setEvaluator();//设置评估者
valueAnimator.setRepeatCount();//设置动画重复的次数
valueAnimator.setInterpolator();//设置动画的插值器;也就是动画如何变化,就像速度的描述加速度一样
valueAnimator.setDuration();//动画的时间
valueAnimator.setStartDelay();//动画在开始之前延迟多少
valueAnimator.setRepeatMode();//动画重复的方式;RESTART:开始-结束 开始-结束;REVERSE:开始-结束-开始
valueAnimator.addListener();//动画的监听
valueAnimator.addUpdateListener();//动画属性值更新的监听
二、ValueAnimator的重要使用:
1.setEvaluator()的方法:
public class IntEvaluator implements TypeEvaluator {
public Integer evaluate(float fraction, Integer startValue, Integer endValue)
{
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
里面有三个参数:
- fraction:这个值是由插值器返回的一个百分比的数值,范围0~1之间
- startValue:起始值
- endValue:结束值
这个评估者的类里面就是返回一个一直在叠加的值,也就是一段时间里面变化的值,如果能得到这个值,是不是很多的动画效果就迎刃而解了,因为View变化的时候,其实就是时期位置在一段时间里面不断的变化,当间隔小于肉眼所感知的峥,就认为是在动
2.addUpdateListener();这个方法就是监听动画在动的过程中的回调,那么这里面应该有我们想要的东西
valueAnimator.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Object animatedValue = animation.getAnimatedValue();//这个不正式我们上面传的
值吗
//在这里面我们是不是可以设置View的透明度,平移,旋转,以及放大,其实一段时间里面这还可以变换颜色
}
});
3.当然颜色变换的评估者系统已经给大家定义好了:
public class ArgbEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24);
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24);
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))));
}
}
大家要做变背景色的效果是不是很简单就可以实现
三、ValueAnimator的高级用法
对一个Point作用:
public class Point {
private float x;
private float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
Point类非常简单,只有x和y两个变量用于记录坐标的位置,并提供了构造方法来设置坐标,以及get方法来获取坐标。接下来定义PointEvaluator,如下所示:
public class PointEvaluator implements TypeEvaluator{
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
Point point = new Point(x, y);
return point;
}
}
可以看到,PointEvaluator同样实现了TypeEvaluator接口并重写了evaluate()方法。其实evaluate()方法中的逻辑还是非常简单的,先是将startValue和endValue强转成Point对象,然后同样根据fraction来计算当前动画的x和y的值,最后组装到一个新的Point对象当中并返回。
这样我们就将PointEvaluator编写完成了,接下来我们就可以非常轻松地对Point对象进行动画操作了,比如说我们有两个Point对象,现在需要将Point1通过动画平滑过度到Point2,就可以这样写:
Point point1 = new Point(0, 0);
Point point2 = new Point(300, 300);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2);
anim.setDuration(5000);
anim.start();
代码很简单,这里我们先是new出了两个Point对象,并在构造函数中分别设置了它们的坐标点。然后调用ValueAnimator的ofObject()方法来构建ValueAnimator的实例,这里需要注意的是,ofObject()方法要求多传入一个TypeEvaluator参数,这里我们只需要传入刚才定义好的PointEvaluator的实例就可以了。
好的,这就是自定义TypeEvaluator的全部用法,掌握了这些知识之后,我们就可以来尝试一下如何通过对Point对象进行动画操作,从而实现整个自定义View的动画效果。
新建一个MyAnimView继承自View,代码如下所示:
public class MyAnimView extends View {
public static final float RADIUS = 50f;
private Point currentPoint;
private Paint mPaint;
public MyAnimView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
@Override
protected void onDraw(Canvas canvas) {
if (currentPoint == null) {
currentPoint = new Point(RADIUS, RADIUS);
drawCircle(canvas);
startAnimation();
} else {
drawCircle(canvas);
}
}
private void drawCircle(Canvas canvas) {
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
}
private void startAnimation() {
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setDuration(5000);
anim.start();
}
}
基本上还是很简单的,总共也没几行代码。首先在自定义View的构造方法当中初始化了一个Paint对象作为画笔,并将画笔颜色设置为蓝色,接着在onDraw()方法当中进行绘制。这里我们绘制的逻辑是由currentPoint这个对象控制的,如果currentPoint对象不等于空,那么就调用drawCircle()方法在currentPoint的坐标位置画出一个半径为50的圆,如果currentPoint对象是空,那么就调用startAnimation()方法来启动动画。
那么我们来观察一下startAnimation()方法中的代码,其实大家应该很熟悉了,就是对Point对象进行了一个动画操作而已。这里我们定义了一个startPoint和一个endPoint,坐标分别是View的左上角和右下角,并将动画的时长设为5秒。然后有一点需要大家注意的,就是我们通过监听器对动画的过程进行了监听,每当Point值有改变的时候都会回调onAnimationUpdate()方法。在这个方法当中,我们对currentPoint对象进行了重新赋值,并调用了invalidate()方法,这样的话onDraw()方法就会重新调用,并且由于currentPoint对象的坐标已经改变了,那么绘制的位置也会改变,于是一个平移的动画效果也就实现了。
下面我们只需要在布局文件当中引入这个自定义控件:
总结:有时候大家可能对一些动画可能很没有头绪,也可能是一些属性变化没有什么头绪,希望鄙人上面所讲的会对你有更大的帮助,你只要知道了思想才可能,应对更对的可能
注意:因为属性动画是API3.0以后的属性;所以在GitHub有大神给出来兼容的属性动画:只要在AS里面依赖:
compile 'com.nineoldandroids:library:2.4.0'