一、前言
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 弹簧动画的监听器
弹簧动画可以添加两个监听器,分别是 OnAnimationUpdateListener
和 OnAnimationEndListener
,用来监听动画的不同状态。分别调用 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
}
}
- 示例效果