重新学习属性动画

375 阅读2分钟

一 补间动画的缺点

  • 没有实质性的改变位置,只是视觉上改变了位置,点击事件依然在以前的位置
  • 补间动画会触发同步屏障,导致一些有关IdleHandler的操作无法执行 , 比如Activity的onStop/onDestroy会延时10s执行
  • 只能执行平移、缩放、旋转 和 透明度 几种系统固定的动画

二 属性动画

2.1 原理

在一定时间间隔内,通过反射不断对值进行改变、不断将该值赋给对象的属性(任意对象的任意属性),并且调用invalidate()进行重绘操作。

2.2 特点

  • 真正的改变了View的位置,及点击事件生效
  • 不会频繁的触发同步屏障,从而导致 IdleHandler 不会去执行
  • 不局限于平移、缩放、旋转 和 透明度 几种系统固定的动画,自己也可以去设置属性
  • API11引入

三 属性动画实现方式

3.1 ViewPropertyAnimator

优点

  • 专门针对View对象动画而操作的类。
  • 更简洁的链式调用设置多个属性动画
  • 多个属性动画是一次同时变化,只执行一次UI刷新(也就是只调用一次invalidate,而n个ObjectAnimator就会进行n次属性变化,就有n次invalidate)
  • View的animate()获取其实例对象的引用
val animate =
            view.animate()
                .translationX(50f.px)
                .translationY(50f.px)
                .scaleX(2f)
                .scaleY(2f)
                .rotation(45f)
                .setDuration(1000)
        animate.startDelay = 1000
        animate.start()

3.2 ObjectAnimator

优点是除了可以更改系统的属性外,也可以更改咱们自定义的属性

3.2.1 实现上面的效果

  val animatorTranslationY = ObjectAnimator.ofFloat(view, "translationY", 50f)
    animatorTranslationY.duration = 2000

    val animatorTranslationX: ObjectAnimator = ObjectAnimator.ofFloat(view, "translationX", 50f)
    animatorTranslationX.duration = 2000

    val animatorScaleX: ObjectAnimator = ObjectAnimator.ofFloat(view, "scaleX", 0.5f)
    animatorScaleX.duration = 2000

    val animatorScaleY: ObjectAnimator = ObjectAnimator.ofFloat(view, "scaleY", 0.5f)
    animatorScaleY.duration = 2000

    val animatorSet= AnimatorSet()
    animatorSet.playTogether(animatorTranslationY,animatorTranslationX,animatorScaleX,animatorScaleY)
    animatorSet.startDelay = 1000
    animatorSet.start()
 

3.2.2 实现自定义属性的效果

定义出自定义类
class MyView(context: Context, attrs: AttributeSet) : View(context, attrs) {
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.BLACK
    }
    // 自定义咱们改变的属性,这里简单的只是改变一下透明度
    var myAlpha = 0f
        set(value) {
            field = value
            // 调用 重绘制
            invalidate()
        }

  


    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.withSave {
            // 使用 myAlpha 进行透明度
            paint.color = Color.argb(myAlpha, 0f, 0f, 0f)
            canvas.drawRect(100f.px, 100f.px, 200f.px, 200f.px, paint)
        }


    }
}
使用,这样就改变了透明度
val animatorSize: ObjectAnimator = ObjectAnimator.ofFloat(view, "myAlpha", 1f)
animatorSize.duration = 2000
animatorSize.startDelay = 1000
animatorSize.start()

3.3 PropertyValuesHolder 和 Keyframe

PropertyValuesHolder 和 Keyframe配合,可以让动画精确到某一帧的效果

// keyframe 可以控制 精确到帧
        val keyframe1 = Keyframe.ofFloat(0.0f, 0f)
        val keyframe2 = Keyframe.ofFloat(0.25f, 1f)
        val keyframe3 = Keyframe.ofFloat(0.5f, 2f)
        val keyframe4 = Keyframe.ofFloat(0.75f, 1f)
        val keyframe5 = Keyframe.ofFloat(1.0f, 2f)
        val scalex = PropertyValuesHolder.ofKeyframe("scaleX", keyframe1,keyframe2,keyframe3,keyframe4,keyframe5)
        val scaleY = PropertyValuesHolder.ofKeyframe("scaleY", keyframe1,keyframe2,keyframe3,keyframe4,keyframe5)
        val animator: ObjectAnimator =
            ObjectAnimator.ofPropertyValuesHolder(view, scalex, scaleY)
        animator.duration = 3000
        animator.startDelay = 1000
        animator.start()

参考

属性动画-Property Animation之ViewPropertyAnimator 你应该知道的一切
Android 属性动画:这是一篇全面 & 详细的 属性动画 总结&攻略