Android valueAnimator和ObjectAnimator浅谈(二)

本文讲解了如何利用自定义TypeEvaluator实现View动画效果,重点介绍了PointEvaluator的具体实现过程及如何结合ValueAnimator创建从屏幕左上角滑动到右下角的小圆圈动画。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天,我们来讲,怎么让一个小圆圈从屏幕左上角慢慢滑到右下角,其实这个网上很多,但里面有许多小知识点,小细节。我觉得可以拿出来讲讲。
在开始讲今天的主题时,我们先来补充一个知识点:

(1)TypeEvaluator类。
那么TypeEvaluator的作用到底是什么呢?简单来说,就是告诉动画系统如何从初始值过度到结束值。我们在上一篇文章中学到的ValueAnimator.ofFloat()方法就是实现了初始值与结束值之间的平滑过度,那么这个平滑过度是怎么做到的呢?其实就是系统内置了一个FloatEvaluator,它通过计算告知动画系统如何从初始值过度到结束值,我们来看一下FloatEvaluator的代码实现:

public class FloatEvaluator implements TypeEvaluator {  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        float startFloat = ((Number) startValue).floatValue();  
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);  
    }  
}  

可以看到,FloatEvaluator实现了TypeEvaluator接口,然后重写evaluate()方法。evaluate()方法当中传入了三个参数,第一个参数fraction非常重要,这个参数用于表示动画的完成度的,我们应该根据它来计算当前动画的值应该是多少,第二第三个参数分别表示动画的初始值和结束值。那么上述代码的逻辑就比较清晰了,用结束值减去初始值,算出它们之间的差值,然后乘以fraction这个系数,再加上初始值,那么就得到当前动画的值了。

好的,那FloatEvaluator是系统内置好的功能,并不需要我们自己去编写,但介绍它的实现方法是要为我们后面的功能铺路的。前面我们使用过了ValueAnimator的ofFloat()和ofInt()方法,分别用于对浮点型和整型的数据进行动画操作的,但实际上ValueAnimator中还有一个ofObject()方法,是用于对任意对象进行动画操作的。但是相比于浮点型或整型数据,对象的动画操作明显要更复杂一些,因为系统将完全无法知道如何从初始对象过度到结束对象,因此这个时候我们就需要实现一个自己的TypeEvaluator来告知系统如何进行过度。

PointEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
    Point pointStart= (Point) startValue;
    Point pointEnd= (Point) endValue;
    float x=pointStart.x+fraction*(pointEnd.x-pointStart.x);
    float y=pointStart.y+fraction*(pointEnd.y-pointStart.y);
    Point point=new Point((int)x,(int)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的动画效果。

自定义的控件:Customeview类:

public class Customeview extends View{
private Point currentPoint;
private Paint paint;
private int REDIUS=50;

public Customeview(Context context, AttributeSet attrs) {
    super(context, attrs);

    //画笔的初始化
    paint=new Paint();
    paint.setAntiAlias(true);
    paint.setColor(Color.BLUE);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (currentPoint==null){
        currentPoint=new Point(REDIUS,REDIUS);
        drawCricle(canvas);//画圆
        startCricleAnimation();//开始动画
    }else {
        drawCricle(canvas);
    }
}

private void drawCricle(Canvas canvas){
    canvas.drawCircle(currentPoint.x,currentPoint.y,REDIUS,paint);

}

private void startCricleAnimation(){
    Point startPoint=new Point(currentPoint.x,currentPoint.y);
    Point endPoint=new Point(getWidth()-REDIUS,getHeight()-REDIUS);
    ValueAnimator valueAnimator= ValueAnimator.ofObject(new PointEvaluator(){},startPoint,endPoint);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            currentPoint= (Point) animation.getAnimatedValue();
            invalidate();
        }
    });

    ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(this,"alpha",1,0,1);

    //把两个动画组合在一起
    AnimatorSet animatorSet=new AnimatorSet();
    animatorSet.play(valueAnimator).with(objectAnimator);
    animatorSet.setDuration(5000);
    animatorSet.start();
}

}

代码都不过多解释了,都是Android valueAnimator和ObjectAnimator浅谈(一)讲过的内容。

(2)xml布局:
你会说,这个也需要讲,请您,继续往下读,会有点小收获。
这里写图片描述

注意看Customeview类的这段代码:

Point endPoint=new Point(getWidth()-REDIUS,getHeight()-REDIUS);
getWidth:代表控件的宽度,那你说上面这段代码:getWidth()-REDIUS为左下角小圆圈圆心X坐标???
我估计应该跟Android 源码设计有关,这个问题后续会做出解释。唯一确定点的是Canvas的大小,就是咱们自定义控件的大小。例如你把:Customeview固定好宽度,高度。那么小圆圈,就只会在这个范围内显示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值