Android中动画之四属性动画高级用法二

一.概况

目的

在上一篇中记录了“对任何类的任何属性进行动画”基础,那只是简单的对属性值(int,float类型)进行动画处理。下面我们对非int,float类型的属性值进行处理。

涉及的知识点

  • 自定义估值器
  • ofObjec和ofArgb方法介绍使用
  • ValueAnimator的高级用法
  • ObjectAnimator的高级用法

二.自定义估值器

2.1先看一个系统自带的估值器FloatEvaluator

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

自定义估值器只要重写evaluate方法就好。

从上面的FloatEvaluator的实现我们可知实现自定义估值器刚需就是重写evaluate方法。下面分析一下其各个参数含义。

分析重写方法中的三个参数

  1. fraction:由插值器获得的动画的完成度
  2. startValue:动画的开始值
  3. endValue:动画的结束值

三.View背景颜色动画

目的

通过View背景颜色动画来熟悉一下ofArgb和ofObject方法。

注意

  • ValueAnimator和ObjectAnimator都有ofArgb方法,其是用来实现颜色变化的只不过它引入的比较晚API21以后才引入。
  • 通过ValueAnimator和ObjectAnimator的ofObject也可以实现背景颜色动画,且兼容性比上面ofArgb方法好。

先看效果

这里写图片描述

实现代码

布局文件很简单这里就不贴了,只是包含一个TextView

四种实现方法

第一种:

使用ObjectAnimator.ofArgb,

    private void startAni() {
        //API21以上能用
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ObjectAnimator ani = ObjectAnimator.ofArgb(showTv,"backgroundColor",0xffff0000,0xff00ff00,0xff0000ff);
            ani.setDuration(4000);
            ani.start();
        }
    }

比较好理解ofArgb前俩个参数一个目标对象,一个属性名称;后面是32位的int值用来表示颜色值。

第二种:

使用ValueAnimator.ofArgb并设置监听器,自己更改背景颜色。

    private void startAni() {
        //API21以上能用
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            ValueAnimator ani = ValueAnimator.ofArgb(0xffff0000,0xff00ff00,0xff0000ff);
            ani.setDuration(4000);
            ani.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    showTv.setBackgroundColor((Integer) animation.getAnimatedValue());
                }
            });
            ani.start();
        }
    }

第三种

使用系统的ArgbEvaluator估值器,这样能提供较好兼容性

    private void startAni() {
        ObjectAnimator ani = ObjectAnimator.ofObject(showTv,"backgroundColor",new ArgbEvaluator(),0xffff0000,0xff00ff00,0xff0000ff);
        ani.setDuration(4000);
        ani.start();
    }

第四种

使用系统的ArgbEvaluator估值器,这样能提供较好兼容性

    private void startAni() {
        ValueAnimator ani = ValueAnimator.ofObject(new ArgbEvaluator(),0xffff0000,0xff00ff00,0xff0000ff);
        ani.setDuration(4000);
        ani.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                showTv.setBackgroundColor((Integer) animation.getAnimatedValue());
            }
        });
        ani.start();
    }

分析

上面的第三种和第四种方法相对第一种,第二种方法提供了较好的兼容性。

四.ValueAnimator的高级用法

4.1背景

通过上一篇Android中动画之三属性动画高级用法一,我们知道对任意类(Object)的任意属性(abc)做动画,想要成功要具备俩个条件如下:
1.Object必须提供setAbc方法;如果动画的时候没有传递初始化值,那么还要有getAbc方法,因为系统要去取abc属性的初始值(如果不满足这个条件,直接crash);
2.Object的setAbc对属性abc所做的改变必须通过某种方法表现出来,最常见的就是UI的变化。(如果不满足这个条件,不会crash,但是没有效果)
我们想要实验一下ValueAnimator的ofObject方法,想要直观的看到动画效果,那我们就要一个使用场景。

4.2场景

在一个自定义View中实现一个圆完成平移动画。可能看起来很简单,但是关键是理解其中的原理。

4.3分析

先看一下ValueAnimator的ofObject方法需要什么

public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)

从上面可知想要对任意类的任意属性做动画,那么我们需要自己的估值器TypeEvaluator,类的属性(这里可以是基本类型如int,float也可以是任何的类)数组;

4.4解决方案

自定义一个View,在里面连续画圆,也就相当于对View的位置类属性进行了动画处理。

4.5效果和具体代码

效果如下图

这里写图片描述

具体代码

圆Pointer(圆就是一个大的点)如下:

主要是坐标属性

public class Pointer {
    private float x;
    private float y;

    public Pointer(float x,float y){
        this.x = x;
        this.y = y;
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }
}

自定义估值器

坐标各自求值,并取得变化后的Pointer对象。

public class PointerEvaluator implements TypeEvaluator<Pointer>{
    @Override
    public Pointer evaluate(float fraction, Pointer startValue, Pointer endValue) {
        float x = startValue.getX() + fraction*(endValue.getX() - startValue.getX());
        float y = startValue.getY() + fraction*(endValue.getY() - startValue.getY());
        return new Pointer(x,y);
    }
}

自定义View

public class AnimatorView extends View{
    private static final float RADIUS = 50;

    private Paint mPaint;
    private Pointer curPointer;

    public AnimatorView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        //初始化画笔
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (curPointer == null){
            //最初
            //初始化圆(位置主要是)
            curPointer = new Pointer(RADIUS,RADIUS);
            //画出来
            drawCicle(canvas);
            //开始动画
            startAni();
        }else {
            drawCicle(canvas);
        }
    }

    private void startAni() {
        Pointer startP = new Pointer(RADIUS,RADIUS);
        Pointer endP = new Pointer(getWidth()-RADIUS,getHeight()-RADIUS);
        final ValueAnimator ani = ValueAnimator.ofObject(new PointerEvaluator(),startP,endP);
        ani.setDuration(4000);
        ani.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                curPointer = (Pointer) animation.getAnimatedValue();
                //关键:获取新位置后调用invalidate,执行画圆操作。
                invalidate();
            }
        });
        ani.start();
    }

    private void drawCicle(Canvas canvas) {
        canvas.drawCircle(curPointer.getX(),curPointer.getY(),RADIUS,mPaint);
    }
}

上面的AnimatorView中流程如下:

  1. 构造方法中初始化画笔
  2. onDraw中判断curPointer是否为空,为空刚进入绘制过程。初始化Pointer;开始画圆;开始动画。
  3. 在动画的回调监听中获取现在圆的位置,调用invalidate重新执行onDraw,周而复始随之动画的进行不断改变圆的位置,达到对圆添加动画的目的。

五.ObjectAnimator的高级用法

实现效果

自定义View中圆平移并且颜色发生变化,这里实现的效果比较简单,用现有的属性动画组合可以实现,但是重点是理解ObjectAnimator的ofObject方法以及自定义估值器。

这里写图片描述

看起来简单,实现起来还是有些要注意的地方的

Activity中对自定义View不做处理,xml中添加自定义View设置宽高为填充满就好。下面几个是关键的类。

自定义View

public class ArgbAndPosView extends View{
    //圆的半径
    private static final int RADIUS = 50;

    //画笔
    private Paint mPaint;
    //自定义View的属性值
    private Pointer pointer;

    //动画属性的get方法
    public Pointer getPointer() {
        return pointer;
    }
    //动画属性的set方法
    public void setPointer(Pointer pointer) {
        this.pointer = pointer;

        //设置颜色值
        mPaint.setColor(pointer.getColor());
        //请求刷新
        invalidate();
    }

    public ArgbAndPosView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        //构造方法中初始化画笔
        initPaint();
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (pointer == null){
            //初次进入,初始化将被进行动画处理的属性值
            pointer = new Pointer(RADIUS,RADIUS,Color.RED);
            //画出来
            drawCircle(canvas);
            //开始动画
            startAni();
        }else {
            //每次刷新都重画
            drawCircle(canvas);
        }
    }

    private void startAni() {
        //起点属性值
        Pointer startP = new Pointer(RADIUS,RADIUS,0xffff0000);
        //终点属性值
        Pointer endP = new Pointer(getWidth()-RADIUS,getHeight()-RADIUS,0xff00ff00);
        //对本自定义View的pointer属性进行动画处理,动画时间为4000毫秒,从startP到endP,插值器用的默认的
        ObjectAnimator ani = ObjectAnimator.ofObject(this,"pointer",new PointerEvaluator(),startP, endP);
        ani.setDuration(4000);
        ani.start();
    }

    //画圆
    private void drawCircle(Canvas canvas) {
        canvas.drawCircle(pointer.getX(),pointer.getY(),RADIUS,mPaint);
    }
}

自定义View中的属性值Pointer

自定义View中将被进行动画处理的属性,这里是个Pointer类。

public class Pointer {
    private float x;
    private float y;
    private int color;

    public Pointer(float x,float y,int color){
        this.x = x;
        this.y = y;
        this.color = color;
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }

    public int getColor() {
        return color;
    }
}

关键,自定义估值器

估值器很重要,分别对Pointer中的属性进行计算处理,获取现在时间点对应的动画属性值。

public class PointerEvaluator implements TypeEvaluator<Pointer>{
    @Override
    public Pointer evaluate(float fraction, Pointer startValue, Pointer endValue) {
        //处理坐标
        float x = startValue.getX() + fraction*(endValue.getX() - startValue.getX());
        float y = startValue.getY() + fraction*(endValue.getY() - startValue.getY());

        //处理颜色,处理过程和ArgbEvaluator中一样
        int startInt = startValue.getColor();
        float startA = ((startInt >> 24) & 0xff) / 255.0f;
        float startR = ((startInt >> 16) & 0xff) / 255.0f;
        float startG = ((startInt >>  8) & 0xff) / 255.0f;
        float startB = ( startInt        & 0xff) / 255.0f;

        int endInt = endValue.getColor();
        float endA = ((endInt >> 24) & 0xff) / 255.0f;
        float endR = ((endInt >> 16) & 0xff) / 255.0f;
        float endG = ((endInt >>  8) & 0xff) / 255.0f;
        float endB = ( endInt        & 0xff) / 255.0f;

        // convert from sRGB to linear
        startR = (float) Math.pow(startR, 2.2);
        startG = (float) Math.pow(startG, 2.2);
        startB = (float) Math.pow(startB, 2.2);

        endR = (float) Math.pow(endR, 2.2);
        endG = (float) Math.pow(endG, 2.2);
        endB = (float) Math.pow(endB, 2.2);

        // compute the interpolated color in linear space
        float a = startA + fraction * (endA - startA);
        float r = startR + fraction * (endR - startR);
        float g = startG + fraction * (endG - startG);
        float b = startB + fraction * (endB - startB);

        // convert back to sRGB in the [0..255] range
        a = a * 255.0f;
        r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
        g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
        b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;

        int color = Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);

        return new Pointer(x,y,color);
    }
}

其实上面的Pointer中还可以添加更多的属性以控制更多的动画效果。

五.总结

通过本文可以掌握:

  • 自定义估值器
  • ofObjec和ofArgb方法介绍使用
  • ValueAnimator的高级用法
  • ObjectAnimator的高级用法
    后两个主要是ofObject方法的用法,也就是对任意类的任意属性进行动画操作。

猜你喜欢

转载自blog.csdn.net/gongxiaoou/article/details/80754165