笔记—自定义View之属性动画进阶篇

概述:本篇将会从两个方面进行属性动画进阶篇的讲解,1 特殊属性的动画,2 复杂属性的动画。

一 特殊属性的动画

一 TypeEvaluator

关于 ObjectAnimator,上期讲到可以用 ofInt() 来做整数的属性动画和用 ofFloat() 来做小数的属性动画。这两种属性类型是属性动画最常用的两种,不过在实际的开发中,可以做属相动画的类型还是有其他的一些类型。当需要对其他类型来做属性动画的时候,就需要用到 TypeEvaluator 了

1 ArgbEvaluator

TypeEvaluator 最经典的用法是使用 ArgbEvaluator 来做颜色渐变的动画

ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xffff0000, 0xff00ff00);  
animator.setEvaluator(new ArgbEvaluator());  
animator.start();

在 Android 5.0 (API 21) 加入了新的方法 ofArgb(),所以如果你的 minSdk 大于或者等于 21,你可以直接用下面这种方式:

ObjectAnimator animator = ObjectAnimator.ofArgb(view, "color", 0xffff0000, 0xff00ff00);  
animator.start();
2 自定义 Evaluator

如果你对 ArgbEvaluator 的效果不满意,或者你由于别的什么原因希望写一个自定义的 TypeEvaluator,你可以这样写:

// 自定义 HslEvaluator
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);
   }
}

ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xff00ff00);  
// 使用自定义的 HslEvaluator
animator.setEvaluator(new HsvEvaluator());  
animator.start();  
3 ofObject()

借助于 TypeEvaluator,属性动画就可以通过 ofObject() 来对不限定类型的属性做动画了

private class PointFEvaluator implements TypeEvaluator<PointF> {  
   PointF newPoint = 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));

       newPoint.set(x, y);

       return newPoint;
   }
}

ObjectAnimator animator = ObjectAnimator.ofObject(view, "position",  
        new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));
animator.start();
ofMultiInt() ofMultiFloat()

在 API 引入的新的方法还有 ofMultiInt() 和 ofMultiFloat() 等,用法也很简单,不过实用性就低了一些

二 复杂属性的动画

一 PropertyValuesHolder 同一个动画中改变多个属性

很多时候,你在同一个动画中会需要改变多个属性,例如在改变透明度的同时改变尺寸。

1 使用 ViewPropertyAnimator,你可以直接用连写的方式来在一个动画中同时改变多个属性
view.animate().scaleX(1).scaleY(1).alpha(1);
2 使用 ObjectAnimator,是不能这么用的。不过你可以使用 PropertyValuesHolder 来同时在一个动画中改变多个属性。
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);  
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);  
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)  
animator.start(); 

PropertyValuesHolder 的意思从名字可以看出来,它是一个属性值的批量存放地。所以你如果有多个属性需要修改,可以把它们放在不同的 PropertyValuesHolder 中,然后使用 ofPropertyValuesHolder() 统一放进 Animator。这样你就不用为每个属性单独创建一个 Animator 分别执行了

二 AnimatorSet 多个动画配合执行

有的时候,你不止需要在一个动画中改变多个属性,还会需要多个动画配合工作,比如,在内容的大小从 0 放大到 100% 大小后开始移动。这种情况使用 PropertyValuesHolder 是不行的,因为这些属性如果放在同一个动画中,需要共享动画的开始时间、结束时间、Interpolator 等等一系列的设定,这样就不能有先后次序地执行动画了

ObjectAnimator animator1 = ObjectAnimator.ofFloat(...);  
animator1.setInterpolator(new LinearInterpolator());  
ObjectAnimator animator2 = ObjectAnimator.ofInt(...);  
animator2.setInterpolator(new DecelerateInterpolator());

AnimatorSet animatorSet = new AnimatorSet();  
// 两个动画依次执行
animatorSet.playSequentially(animator1, animator2);  
animatorSet.start();
// 两个动画同时执行
animatorSet.playTogether(animator1, animator2);  
animatorSet.start(); 
// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)
// 的方式来精确配置各个 Animator 之间的关系
animatorSet.play(animator1).with(animator2);  
animatorSet.play(animator1).before(animator2);  
animatorSet.play(animator1).after(animator2);  
animatorSet.start();

三 PropertyValuesHolders.ofKeyframe() 把同一个属性拆分

除了合并多个属性和调配多个动画,你还可以在 PropertyValuesHolder 的基础上更进一步,通过设置 Keyframe (关键帧),把同一个动画属性拆分成多个阶段。例如,你可以让一个进度增加到 100% 后再「反弹」回来。

四 ValueAnimator 最基本的轮子

除了 ViewPropertyAnimator 和 ObjectAnimator,还有第三个选择是 ValueAnimator。ValueAnimator 并不常用,因为它的功能太基础了。ValueAnimator 是 ObjectAnimator 的父类,实际上,ValueAnimator 就是一个不能指定目标对象版本的 ObjectAnimator。ObjectAnimator 是自动调用目标对象的 setter 方法来更新目标属性的值,以及很多的时候还会以此来改变目标对象的 UI,而 ValueAnimator 只是通过渐变的方式来改变一个独立的数据,这个数据不是属于某个对象的,至于在数据更新后要做什么事,全都由你来定,你可以依然是去调用某个对象的 setter 方法(别这么为难自己),也可以做其他的事,不管要做什么,都是要你自己来写的,ValueAnimator 不会帮你做。功能最少、最不方便,但有时也是束缚最少、最灵活。比如有的时候,你要给一个第三方控件做动画,你需要更新的那个属性没有 setter 方法,只能直接修改,这样的话 ObjectAnimator 就不灵了啊。怎么办?这个时候你就可以用 ValueAnimator,在它的 onUpdate() 里面更新这个属性的值,并且手动调用 invalidate()。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值