一、前言

    Android提供了动力学动画(DynamicAnimation)的支持,这类动画具有物理动力学的相关特性(而不是普通线性变化),其中弹簧动画(SpringAnimation)就是一种。顾名思义,弹簧动画就是符合弹簧收缩特性的动画。

二、使用弹簧动画

2.1 引入依赖库

    动力学动画并不在系统框架库中,使用时必须引入依赖库。

// 以下是 support 库版本
// implementation 'com.android.support:support-dynamic-animation:28.0.0'

// 以下是 androidx 版本
// Java
// implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
// kotlin
implementation 'androidx.dynamicanimation:dynamicanimation-ktx:1.0.0-alpha03'

注意:
1. support 库和 androidx 库不能同时使用;
2.依赖库的最新版本以官方为准。

2.2 创建弹簧动画

    创建弹簧动画主要是构建 SpringAnimation 类实例,创建对象时需要指定一个添加动画的对象属性,添加动画属性的最终值和需要添加动画的对象,并可以根据需要设置各种参数和监听。

  • 可添加弹簧动画的对象属性有(在 DynamicAnimation 类中定义):
  • ALPHA:视图的透明度,取值 0 ~ 1,默认值是1(不透明),取值 0 时为不可见。
  • TRANSLATION_X:X坐标位移动画。
  • TRANSLATION_Y:Y坐标位移动画。
  • TRANSLATION_Z:Z坐标位移动画。
  • SCROLL_X: X 轴滚动动画。
  • SCROLL_Y: Y 轴滚动动画。
  • X: Z 坐标值变更动画。
  • Y: Y 坐标值变更动画。
  • Z: Z 坐标值变更动画。
  • 示例(Y轴移动动画)
findViewById<View>(R.id.imageView).apply {
    var y = 0f
    var dy: Float
    var startValue = 0f
    // 添加手势,滑动时向下移动对象,当手放开时,向上采用弹簧动画恢复到原位
    setOnTouchListener { v, event ->
        when(event.action) {
            MotionEvent.ACTION_DOWN -> {
                startValue = 0f
                y = event.rawY
            }

            MotionEvent.ACTION_MOVE -> {
                dy = event.rawY - y
                y = event.rawY
                v.y = v.y + dy
                startValue += dy
            }

            MotionEvent.ACTION_UP -> {
                // 创建一个 SpringAnimation 类实例,
                SpringAnimation(v, DynamicAnimation.TRANSLATION_Y, 0f).apply {
                    setStartValue(startValue)
                    spring.dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
                    start()
                }
            }
        }
        true
    }
  • 效果

说明:弹簧动画指的是动画特效规则符合弹簧弹跳规则,不仅仅是位移方面的动画,还可以包括透明度、滚动等。

2.3 弹簧动画的监听器

    弹簧动画可以添加两个监听器,分别是 OnAnimationUpdateListenerOnAnimationEndListener,用来监听动画的不同状态。分别调用 addUpdateListener()addEndListener() 方法进行设置。

2.3.1 OnAnimationUpdateListener

    OnAnimationUpdateListener 监听跟其他动画中的一样,在动画过程中属性值发生变化是回调 onAnimationUpdate() 方法,通过重写回调方法,可以实现需要的逻辑。

2.3.2 OnAnimationEndListener

    OnAnimationEndListener 监听是在动画播放完毕的时候回调 onAnimationEnd() 方法,通过重写回调方法,可以在动画播放完毕时实现需要的逻辑。

2.4 配置动画参数

2.4.1 设置动画起始值

    动画的起始值是指添加动的画属性的初始值,可以调用 setStartValue() 方法设置。如果未设置起始值,则动画将使用对象属性的当前值作为起始值。

2.4.2 设置动画最大值和最小值

    设置添加动画属性的最大值和最小值,设置之后动画将会在最大值和最小值之间变化(例如透明度是0 ~ 1之间,但是你可以设置成0.5 ~ 1,用来让对象一直处于可见状态)

  • 要设置最小值,调用 setMinValue() 方法。
  • 要设置最大值,调用 setMaxValue() 方法。

2.4.3 设置起始速度

    起始速度是指动画开始时动画属性更改的速度。默认起始速度为 0 像素/秒(由静止开始运动)。开发者可以根据实际情况设置起始速度,比如手势移动物体,释放时以释放时的速度为初始速度,也可以将起始速度设置为固定值,如果选择固定值作为起始速度,建议使用 dp/秒 为单位定义该值,然后将其转换为以 px/秒 为单位(以dp/秒 为单位定义该值可使速度与密度和外形规格无关)。

调用 setStartVelocity() 方法设置动画起始速度(以 px/秒 为单位)。

findViewById<View>(R.id.imageView).apply {
    var y = 0f
    var dy: Float
    var startValue = 0f
    // 添加手势,滑动时向下移动对象,当手放开时,向上采用弹簧动画恢复到原位
    setOnTouchListener { v, event ->
        when(event.action) {
            MotionEvent.ACTION_DOWN -> {
                startValue = 0f
                y = event.rawY
            }

            MotionEvent.ACTION_MOVE -> {
                dy = event.rawY - y
                y = event.rawY
                v.y = v.y + dy
                startValue += dy
            }
            MotionEvent.ACTION_UP -> {
                SpringAnimation(v, DynamicAnimation.TRANSLATION_Y, 0f).apply {
                    setStartValue(startValue)
                    setStartVelocity(0.0f)
                    spring.dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
                    start()
                }
            }
        }
        true
    }
}

2.4.4 设置弹簧属性

    弹簧的属性有两个,一个是阻尼比,一个是强度。阻尼比是指弹簧震动衰减的状况,取值 0 ~ 1,值越大,震动衰减越快,就越快回到静止位置(若取值为0时无阻尼,将无限循环震动);刚度是指弹簧拉力强度,强度越大,回弹力就越大,弹簧震动速度就越快。
    要设置弹簧动画的弹簧属性,首先要通过 getSpring() 方法获取到弹簧对象(SpringForce),然后通过对应的 setter 方法设置属性。

  • 设置阻尼比
    调用 SpringForce 对象的 setDampingRatio() 方法设置阻尼比,阻尼比是一个 0 ~ 1 之间的浮点数,系统已经提供了部分阻尼比常量(系统定义为弹性,弹性越高,阻尼比越小),开发者也可以根据情况自己定义阻尼比。
  • SpringForce.DAMPING_RATIO_HIGH_BOUNCY:高弹性阻尼比(低阻尼)
  • SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY:中弹性阻尼比(中阻尼)
  • SpringForce.DAMPING_RATIO_LOW_BOUNCY:低弹性阻尼比(高阻尼)
  • SpringForce.DAMPING_RATIO_NO_BOUNCY:无弹性阻尼比(最大阻尼,取值1)

注意:阻尼比越小,弹性越好。阻尼比必须为非负数,取值 0 ~ 1,当取值0时无阻尼,也就是弹簧震动就会永远继续下去。

  • 设置弹簧强度
    调用 SpringForce 对象的 setStiffness() 方法设置弹簧强度,系统定义了部分强度常量,开发者也可以自己定义一个数值。
  • SpringForce.STIFFNESS_HIGH:高强度(10000)
  • SpringForce.STIFFNESS_MEDIUM:中强度(1500)
  • SpringForce.STIFFNESS_LOW:低强度(200)
  • SpringForce.STIFFNESS_VERY_LOW:非常低强度(50)
  • 示例
findViewById<View>(R.id.imageView).apply {
    var y = 0f
    var dy: Float
    var startValue = 0f
    // 添加手势,滑动时向下移动对象,当手放开时,向上采用弹簧动画恢复到原位
    setOnTouchListener { v, event ->
        when(event.action) {
            MotionEvent.ACTION_DOWN -> {
                startValue = 0f
                y = event.rawY
            }

            MotionEvent.ACTION_MOVE -> {
                dy = event.rawY - y
                y = event.rawY
                v.y = v.y + dy
                startValue += dy
            }
            MotionEvent.ACTION_UP -> {
                SpringAnimation(v, DynamicAnimation.TRANSLATION_Y, 0f).apply {
                    setStartValue(startValue)
                    setStartVelocity(0.0f)
                    // 设置阻尼比
                    spring.dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
                    // 设置强度
                    spring.stiffness = SpringForce.STIFFNESS_LOW
                    start()
                }
            }
        }
        true
    }
}
  • 示例效果

android ValueAnimator 动画执行卡顿 android 动画引擎_动画