美文网首页
动画合集之属性动画——进阶

动画合集之属性动画——进阶

作者: 巫师Android | 来源:发表于2020-09-20 10:27 被阅读0次

本文的目标是掌握:
1、Evaluator是什么,以及它的自定义和使用
2、Interpolator的自定义
3、知道View可以通过ViewPropertyAnimator进行属性设置

1.Evaluator自定义

调用ValueAnimator的ofInt(),ofFloat()或ofObject()静态方法创建ValueAnimator实例!

在例子中,ofInt和ofFloat我们都用到了,分别用于对浮点型和整型的数据进行动画操作!

那么ofObject()?初始对象和结束对象?如何过渡法?或者说这玩意怎么用?

好的,带着疑问,我们先来了解一个东西:Evaluator,在属性动画概念叨叨逼处其实我们就说到了这个东西:

image

用来告诉动画系统如何从初始值过渡到结束值!好的,我们的入手点没错! 我们进去IntEvaluator的源码,看下里面写了些什么?

image

嗯,实现了TypeEvaluator接口,然后重写了evaluate()方法,参数有三个,依次是:

  • fraction:动画的完成度,我们根据他来计算动画的值应该是多少
  • startValue:动画的起始值
  • endValue:动画的结束值

动画的值 = 初始值 + 完成度 * (结束值 - 初始值)

同样的还有FloatEvaluator,我们想告诉系统如何从初始对象过度到结束对象,那么我们就要 自己来实现TypeEvaluator接口,即自定义Evaluator了,说多无益,写个例子来看看:

2)使用示例

运行效果图

image

代码实现

定义一个对象Point.java,对象中只有x,y两个属性以及get,set方法~

public class Point {

    private float x;
    private float y;

    public Point() {
    }

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

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }

    public void setX(float x) {
        this.x = x;
    }

    public void setY(float y) {
        this.y = y;
    }
}

接着自定义Evaluator类:PointEvaluator.java,实现接口重写evaluate方法~

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

然后自定义一个View类:AnimView.java,很简单~

public class AnimView extends View {

    public static final float RADIUS = 80.0f;
    private Point currentPoint;
    private Paint mPaint;

    public AnimView(Context context) {
        this(context, null);
    }

    public AnimView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AnimView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }

    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(3000l);
        anim.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }
}

最后MainActivity.java处实例化这个View即可~

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new AnimView(this));
    }
}

3)示例增强版

我们上面示例的基础上加上圆移动时的颜色变化~ 这里我们另外用一个ObjectAnimator来加载颜色变化的动画,我们在View中加多个 int color来控制颜色,另外写上getColor()和setColor()的方法,我们先来自定义个Evaluator吧~

运行效果图

image

实现代码

ColorEvaluator.java

public class ColorEvaluator implements TypeEvaluator<Integer>{
    @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int alpha = (int) (Color.alpha(startValue) + fraction *
                (Color.alpha(endValue) - Color.alpha(startValue)));
        int red = (int) (Color.red(startValue) + fraction *
                (Color.red(endValue) - Color.red(startValue)));
        int green = (int) (Color.green(startValue) + fraction *
                (Color.green(endValue) - Color.green(startValue)));
        int blue = (int) (Color.blue(startValue) + fraction *
                (Color.blue(endValue) - Color.blue(startValue)));
        return Color.argb(alpha, red, green, blue);
    }
}

然后自定义View那里加个color,get和set方法;创建一个ObjectAnimator, 和AnimatorSet,接着把动画组合到一起就到,这里就加点东西而已,怕读者有问题, 直接另外建个View吧~

AnimView2.java:

public class AnimView2 extends View {

    public static final float RADIUS = 80.0f;
    private Point currentPoint;
    private Paint mPaint;
    private int mColor;

    public AnimView2(Context context) {
        this(context, null);
    }

    public AnimView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AnimView2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }



    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();
            }
        });

        ObjectAnimator objectAnimator = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(),
                Color.BLUE, Color.RED);
        //动画集合将前面两个动画加到一起,with同时播放
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(anim).with(objectAnimator);
        animatorSet.setStartDelay(1000l);
        animatorSet.setDuration(3000l);
        animatorSet.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }

    //color的get和set方法~
    public int getColor() {
        return mColor;
    }

    public void setColor(int color) {
        mColor = color;
        mPaint.setColor(color);
    }
}

然后MainActivity,setContentView那里把AnimView改成AnimView2就好~

注:

getWidth(),getHeight()在构造方法中取的话,其值还是0,0。在onMeasure后才有值,因此动画的启动要放到onDraw里面。

二、自定义Interpolator

private class DecelerateAccelerateInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        if (input < 0.5) {
            return (float) (Math.sin(input * Math.PI) / 2);
        } else {
            return 1 - (float) (Math.sin(input * Math.PI) / 2);
        }
    }
}

三、ViewPropertyAnimator

3.1后系统当中附增的一个新的功能,为View的动画操作提供一种更加便捷的用法! 假如是以前,让一个TextView从正常状态变成透明状态,会这样写:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);  
animator.start();

而使用ViewPropertyAnimator来实现同样的效果则显得更加易懂:

textview.animate().alpha(0f); 

还支持连缀用法,组合多个动画,设定时长,设置Interpolator等~

textview.animate().x(500).y(500).setDuration(5000)  
        .setInterpolator(new BounceInterpolator());

四、总结

Evaluator的自定义其实就是我们自己定义数值的变化规律。

要熟练掌握动画,还是需要多撸代码,熟练了就简单了。

写于:2020/09/18

相关文章

网友评论

      本文标题:动画合集之属性动画——进阶

      本文链接:https://www.haomeiwen.com/subject/lzjkjktx.html