属性动画 让 APP 动起来

在 APP 开发中很多效果往往都需要动画的配合来实现。 Android 提供了多种动画类型,如属性动画视图动画,其中视图动画又包括帧动画和补间动画。

属性动画说实话没什么高大上的,它的原理也很简单粗暴,无非就是通过不断调用 setXxx 方法修改对象的 属性值(比如 translationXalpha 等等),并配合重绘,以达到动画的效果。

ViewPropertyAnimator

想让一个 View 动起来,可以用 ViewPropertyAnimator 简单实现。通过 View.animate() 可以返回一个 ViewPropertyAnimator 对象,拿到它之后就可以 为所欲为 操作 View 了 。

1
2
3
4
public ViewPropertyAnimator animate() {  
throw new RuntimeException("Stub!");
}
view.animate().translationX(500);//让 view 水平移动500

基本用法

因为属性动画是通过不断操作 View 的属性来实现效果的,所以 ViewPropertyAnimator 的许多方法和 View 的设置属性的相关方法基本相对应。

ViewPropertyAnimator 方法 功能 View 中方法
translationX() translationXBy() 设置 x 轴偏移 setTranslationX()
translationY() translationYBy() 设置 y 轴偏移 setTranslationY()
translationZ() translationZBy() 设置 z 轴偏移 setTranslationZ()
x() xBy() 修改view 的X坐标 setX()
……懒得写了,和上面大差不差 …… ……
rotation() rotationBy() 旋转 View ,正值顺时针 setRotation()
rotationX() rotationXBy() 绕x轴旋转 setRotationX()
rotationY() rotationYBy() 绕Y轴旋转 setRotationY()
scaleX() scaleXBy() 设置横向放缩 setScaleX()
scaleY() scaleYBy() 设置纵向放缩 setScaleY()
alpha() alphaBy() 设置透明度 setAlpha()

说明:

  1. 这里方法参数大部分是 Float ,所以就放空了……
  2. By 的话表示 相对变化(在当前状态基础上增加或减少),比如 translationXBy(50) 表示用动画把 ViewtranslationX 值渐变地增加 50
  3. 顺带提一嘴 Anroid 的 View 系统使用的是左手坐标系。后面如果有写一些关于自定义 View 方面的想法再细谈 View 吧。
方法 功能
setDuration() 设置动画时长
setInterpolator() 设置插值器
start() 开始动画
cancel() 取消动画
setStartDelay() 设置延迟开始时间

插值器

我们可以通过 setInterpolator() 来设置动画的速度模型。 如果想简单体验各种插值器对平移、旋转、缩放、透明度变化的效果,可以访问这个网站玩一玩,一般常用的插值器都有:

Android 动画插值器的在线可视化调试和预览工具。 对于没有指定插值器的动画,默认使用的是 AccelerateDecelerateInterpolator ,实现的效果和它名字差不多,就是先加速再减速。 如果想自定义速度模型的话 *超级大神啊/(ㄒoㄒ)/*~~ ,可以用 PathInterpolator ,传个Path 就行了。

监听器

有时候我们想在动画执行的合适时机做点什么,可以使用监听器。

是啊,做点什么啊?

1.setListener(Animator.AnimatorListener listener)

这个方法需要你去实现一个 Animator.AnimatorListener 接口,但是 —— 这货 特么 要重写四个回调方法……

  • onAnimationStart 动画开始执行时调用
  • onAnimationEnd 动画结束时调用
  • onAnimationCancel 动画被通过 cancel() 取消时调用
  • onAnimationRepeat 重复执行时调用

(ps: ViewPropertyAnimator 不支持重复,所以这个方法对它无效)

当然如果只想监听结束回调啥的,不想写一堆空方法,用 AnimatorListenerAdapter 就行,它是一个适配器类,已经对所有方法提供了空实现,这样我们就可以按需重写方法啦。

1
2
3
4
5
6
7
8
view.animate() 
.translationX(500f)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator{
// 动画结束后执行的逻辑,如跳转页面或执行下一个动画等等
Log.d("Animation", "动画结束")
}
})

2.setUpdateListener(ValueAnimator.AnimatorUpdateListener listener)

它要重写 onAnimationUpdate(ValueAnimator animation) 当动画的属性更新时这个方法被调用。 此外我们可以通过 animation.getAnimatedValue() 拿到当前动画计算出的属性值。

3.withStartAction(Runnable runnable)

设置一个在动画开始时执行的 Runnable

4.withEndAction(Runnable runnable)

设置一个在动画结束时执行的 Runnable,它在动画正常结束时才会被调用,而在动画被cancel() 的话是不会被执行的。

这俩是一次性的,动画执行用完就扔了,之后再重用 ViewPropertyAnimator 来做别的动画,用它们设置的回调也不会再被调用。而 setListener() 所设置的 AnimatorListener持续有效的,当动画重复执行时,回调总会被调用。

ObjectAnimator

最后提一嘴 ObjectAnimator ,它的动画功能更强大,可以实现更多复杂的动画。而且它不依赖 View ,可以作用于任何对象。 当然,这个对象必须拥有对应属性的 setter 方法(如果有初始值还需要 getter 方法)。 码字结束,有空再写吧~