本文主要是学习笔记,学习建议直接去看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();
效果
逗逼的渐变
:
确实实现了渐变,但绝对是在逗逼。因为系统会把色值从0xffff0000按Int直接做加法到0xff00ff00,但效果看起来绝不是我们想要的渐变。我们需要的是人类感觉的渐变,而不是机器所谓的渐变。这里需要制定动画按什么规则变,就需要用到TypeEvaluator,比如添加如下设置:
animator.setEvaluator(new ArgbEvaluator());
这样,就使用系统提供好的ArgbEvaluator实现了人眼感觉的渐变:
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());
效果:
hsv变化规则
再来个简单的自定义TypeEvaluator,帮助理解,比如要是下面效果:
自定义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