使用方式:View.animate() 后跟 translationX() 等方法,动画会自动执行
。canvas
view.animate().translationX(500);
复制代码
使用方式:bash
setter
方法的最后调用invalidate()
方法,刷新绘制;public class SportsView extends View {
float progress = 0;
......
// 建立 getter 方法
public float getProgress() {
return progress;
}
// 建立 setter 方法
public void setProgress(float progress) {
this.progress = progress;
invalidate();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
......
canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint);
......
}
}
......
// 建立 ObjectAnimator 对象
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65);
// 执行动画
animator.start();
复制代码
给动画设置监听器,能够在关键时刻获得反馈,从而及时作出合适的操做,例如在动画的属性更新时同步更新其余数据,或者在动画结束后回收资源等。ide
设置监听器的方法, ViewPropertyAnimator
和 ObjectAnimator
略微不同: ViewPropertyAnimator
用的是 setListener()
和 setUpdateListener()
方法,能够设置一个监听器
,要移除监听器时经过 set[Update]Listener(null) 填 null 值来移除;而 ObjectAnimator
则是用 addListener()
和 addUpdateListener()
来添加一个或多个监听器
,移除监听器则是经过 remove[Update]Listener() 来指定移除对象。post
另外,因为 ObjectAnimator
支持使用 pause()
方法暂停,因此它还多了一个 addPauseListener() / removePauseListener()
的支持; 而 ViewPropertyAnimator
则独有 withStartAction()
和 withEndAction()
方法,能够设置一次性的动画开始或结束的监听,在动画执行结束后就自动丢弃,就算以后再重用 ViewPropertyAnimator
来作别的动画,用它们设置的回调也不会再被调用。而 set/addListener() 所设置的 AnimatorListener 是持续有效的,当动画重复执行时,回调总会被调用。性能
须要说明一下的是,就算动画被取消,onAnimationEnd()
也会被调用。因此当动画被取消时,若是设置了 AnimatorListener
,那么 onAnimationCancel()
和 onAnimationEnd()
都会被调用。onAnimationCancel()
会先于 onAnimationEnd()
被调用。动画
withEndAction()
设置的回调只有在动画正常结束时才会被调用,而在动画被取消时不会被执行。这点和 AnimatorListener.onAnimationEnd()
的行为是不一致的。ui
关于 ObjectAnimator
,上面讲到能够用 ofInt()
来作整数的属性动画和用ofFloat()
来作小数的属性动画。这两种属性类型是属性动画最经常使用的两种,不过在实际的开发中,能够作属相动画的类型仍是有其余的一些类型。当须要对其余类型来作属性动画的时候,就须要用到 TypeEvaluator
了。this
借助于 TypeEvaluator
,属性动画就能够经过 ofObject()
来对不限定类型的属性作动画了。方式很简单:lua
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();
复制代码
不少时候,你在同一个动画中会须要改变多个属性,例如在改变透明度的同时改变尺寸。若是使用 ViewPropertyAnimator,你能够直接用连写的方式来在一个动画中同时改变多个属性:spa
view.animate()
.scaleX(1)
.scaleY(1)
.alpha(1);
复制代码
使用 PropertyValuesHolder
来同时在一个ObjectAnimator
动画中改变多个属性。
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();
复制代码
有的时候,你不止须要在一个动画中改变多个属性,还会须要多个动画配合工做,好比,在内容的大小从 0 放大到 100% 大小后开始移动。这种状况使用 PropertyValuesHolder
是不行的,由于这些属性若是放在同一个动画中,须要共享动画的开始时间、结束时间、Interpolator 等等一系列的设定,这样就不能有前后次序地执行动画了。
这就须要用到 AnimatorSet 了。
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();
复制代码
// 在 0% 处开始
Keyframe keyframe1 = Keyframe.ofFloat(0, 0);
// 时间通过 50% 的时候,动画完成度 100%
Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);
// 时间见过 100% 的时候,动画完成度倒退到 80%,即反弹 20%
Keyframe keyframe3 = Keyframe.ofFloat(1, 80);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);
animator.start();
复制代码
额外简单说一下 ValuesAnimator
。不少时候,你用不到它,只是在你使用一些第三方库的控件,而你想要作动画的属性却没有 setter / getter
方法的时候,会须要用到它。
ValueAnimator 并不经常使用,由于它的功能太基础了。ValueAnimator 是 ObjectAnimator 的父类,实际上,ValueAnimator 就是一个不能指定目标对象版本的 ObjectAnimator。
ObjectAnimator 是自动调用目标对象的 setter 方法来更新目标属性的值,以及不少的时候还会以此来改变目标对象的 UI,而 ValueAnimator 只是经过渐变的方式来改变一个独立的数据,这个数据不是属于某个对象的,至于在数据更新后要作什么事,全都由你来定,你能够依然是去调用某个对象的 setter 方法(别这么为难本身),也能够作其余的事,无论要作什么,都是要你本身来写的,ValueAnimator 不会帮你作。
好比有的时候,你要给一个第三方控件作动画,你须要更新的那个属性没有 setter 方法,只能直接修改,这样的话 ObjectAnimator 就不灵了啊。怎么办?这个时候你就能够用 ValueAnimator
,在它的 onUpdate()
里面更新这个属性的值,而且手动调用 invalidate()
。
因此,ViewPropertyAnimator、ObjectAnimator、ValueAnimator 这三种 Animator,它们实际上是一种递进的关系:从左到右依次变得更加难用,也更加灵活。但我要说明一下,它们的性能是同样的,由于 ViewPropertyAnimator 和 ObjectAnimator 的内部实现其实都是 ValueAnimator,ObjectAnimator 更是原本就是 ValueAnimator 的子类,它们三个的性能并无差异。它们的差异只是使用的便捷性以及功能的灵活性。因此在实际使用时候的选择,只要遵循一个原则就行:尽可能用简单的。
能用 View.animate() 实现就不用 ObjectAnimator,能用 ObjectAnimator 就不用 ValueAnimator。