View属性动画(进阶)

本文主要是学习笔记,学习建议直接去看HenCoder视频教学
作业原地址:课程作业地址
交作业地址:交作业

ObjectAnimator的两个知识点:

  • PropertyValuesHolder和AnimatorSet的使用
  • TypeEvaluator的使用
PropertyValuesHolder和AnimatorSet的使用:

View属性动画(基础)中写到了ViewPropertyAnimator的组合动画,直接连续设置就可以了,会使用相同的Interpolator和Duration。
ObjectAnimator的组合动画需要用到PropertyValuesHolder:

  PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 0, 1);
  PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 0, 1);
  PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 0, 1);
  ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3);
  objectAnimator.start();

但是有时候需求不是这样的,需要每个动画使用不同Interpolator或Duration。使用AnimatorListener当然可以实现,但是还有更简单的实现方式,需要使用AnimatorSet。
比如:

// 要求 1: animator1 先执行,animator2 在 animator1 完成后立即开始
// 要求 2: animator2 和 animator3 同时开始
  ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "alpha", 0, 1);
  ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "translationX", 0, 100);
  ObjectAnimator animator3 = ObjectAnimator.ofFloat(view, "rotation", 0, 360);

使用AnimatorSet实现方式:

  AnimatorSet animatorSet = new AnimatorSet();
  animatorSet.play(animator1).before(animator2);
  animatorSet.play(animator2).with(animator3);
  animatorSet.start();

PropertyValuesHolder还有个比较常用的功能:通过ofKeyframe(),设置关键帧。比如假设有个ProgressView类,需要实现progress的回弹效果:

  Keyframe startFrame = Keyframe.ofFloat(0f, 0);
  Keyframe middleFrame = Keyframe.ofFloat(0.5f, 100);
  Keyframe endFrame = Keyframe.ofFloat(1f, 80);
  PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("progress", startFrame, middleFrame, endFrame);

  ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolder);
  objectAnimator.start();

这样效果就到达了,从0开始,动画执行到一半的时候,进度已经达到100,然后在剩下的时间回弹到80。

TypeEvaluator的使用

TypeEvaluator是干什么的?为什么要用TypeEvaluator?
TypeEvaluator能根据动画属性数值的变换,达到我们想要的效果,系统已经提供了一些TypeEvaluator,我们可以自定义TypeEvaluator。
举个例子,用ObjectAnimator去设置红色渐变为绿色,色值是ofInt,那啥都不管,直接这样撸:

  ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xffff0000, 0xff00ff00);
  animator.setDuration(2000);
  animator.start();

效果
《View属性动画(进阶)》 逗逼的渐变

确实实现了渐变,但绝对是在逗逼。因为系统会把色值从0xffff0000按Int直接做加法到0xff00ff00,但效果看起来绝不是我们想要的渐变。我们需要的是人类感觉的渐变,而不是机器所谓的渐变。这里需要制定动画按什么规则变,就需要用到TypeEvaluator,比如添加如下设置:

animator.setEvaluator(new ArgbEvaluator());

这样,就使用系统提供好的ArgbEvaluator实现了人眼感觉的渐变:

《View属性动画(进阶)》 argb变化规则

或者不使用系统的ArgbEvaluator,想hsv变换规则,自定义HsvEvaluator:

    private class HsvEvaluator implements TypeEvaluator<Integer> {
        float[] startHsv = new float[3];
        float[] endHsv = new float[3];
        float[] outHsv = new float[3];

        @Override
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            // 把 ARGB 转换成 HSV
            Color.colorToHSV(startValue, startHsv);
            Color.colorToHSV(endValue, endHsv);

            // 计算当前动画完成度(fraction)所对应的颜色值
            if (endHsv[0] - startHsv[0] > 180) {
                endHsv[0] -= 360;
            } else if (endHsv[0] - startHsv[0] < -180) {
                endHsv[0] += 360;
            }
            outHsv[0] = startHsv[0] + (endHsv[0] - startHsv[0]) * fraction;
            if (outHsv[0] > 360) {
                outHsv[0] -= 360;
            } else if (outHsv[0] < 0) {
                outHsv[0] += 360;
            }
            outHsv[1] = startHsv[1] + (endHsv[1] - startHsv[1]) * fraction;
            outHsv[2] = startHsv[2] + (endHsv[2] - startHsv[2]) * fraction;

            // 计算当前动画完成度(fraction)所对应的透明度
            int alpha = startValue >> 24 + (int) ((endValue >> 24 - startValue >> 24) * fraction);

            // 把 HSV 转换回 ARGB 返回
            return Color.HSVToColor(alpha, outHsv);
        }
    }
animator.setEvaluator(new HsvEvaluator());

效果:

《View属性动画(进阶)》 hsv变化规则

再来个简单的自定义TypeEvaluator,帮助理解,比如要是下面效果:

《View属性动画(进阶)》

自定义View中:

    public PointF getPosition() {
        return position;
    }

    public void setPosition(PointF position) {
        if (position != null) {
            this.position.set(position);
            invalidate();
        }
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float innerPaddingLeft = RADIUS * 1;
        float innterPaddingRight = RADIUS * 1;
        float innterPaddingTop = RADIUS * 1;
        float innterPaddingBottom = RADIUS * 3;
        float width = getWidth() - innerPaddingLeft - innterPaddingRight - RADIUS * 2;
        float height = getHeight() - innterPaddingTop - innterPaddingBottom - RADIUS * 2;

        canvas.drawCircle(innerPaddingLeft + RADIUS + width * position.x, innterPaddingTop + RADIUS + height * position.y, RADIUS, paint);
    }

自定义PointFEvaluator:

    private class PointFEvaluator implements TypeEvaluator<PointF> {

        PointF pointF = new PointF();
        @Override
        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
            float x = startValue.x + (fraction * (endValue.x - startValue.x));
            float y = startValue.y + (fraction * (endValue.y - startValue.y));
            pointF.set(x, y);
            return pointF;
        }
    }

设置动画:

  ObjectAnimator animator = ObjectAnimator.ofObject(view, "position",
                        new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));
  animator.setInterpolator(new LinearInterpolator());
  animator.setDuration(1000);
  animator.start();

哦了,感谢HenCoder

    原文作者:CoderYuZ
    原文地址: https://www.jianshu.com/p/bbfc34518841
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞