SpringAnimation和FlingAnimation一樣,是DynamicAnimation的兩種型別。Spring模擬的是物理世界的彈力,彈彈彈,彈走魚尾紋,,,
先看下效果:
在某些引數下,可以看到圖片有來回震盪的效果。
SpringAnimation的基本使用
- 新增支援庫
dependencies {
implementation 'com.android.support:support-dynamic-animation:28.0.0'
}
複製程式碼
- 程式碼實現
SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f)
複製程式碼
SpringForce
SpringForce定義著動畫的各種屬性值,其中有兩個重要的屬性:DampingRatio和Stiffness。
DampingRatio可以理解成反彈次數,值越大,反彈次數越少;值為1,則不反彈。
Stiffness可以理解成要恢復成未拉伸狀態所需的時間,值越大,恢復到之前的狀態的時間就越短。
DampingRatio為0將無限震盪,就是無阻尼狀態。這個時候是不能通過skipToEnd()取消動畫的。
Demo中的例子就是調節這兩個屬性,然後就會有不同的效果。
程式碼如下:
class SpringAnimationActivity : AppCompatActivity() {
lateinit var xSpringAnimation: SpringAnimation
lateinit var ySpringAnimation: SpringAnimation
var xDiffLeft: Float? = null
var yDiffTop: Float? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_spring_animation)
val springForce = SpringForce(0f).apply {
setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY)
setStiffness(SpringForce.STIFFNESS_HIGH)
}
dampingRatioGroup.setOnCheckedChangeListener { group, checkedId ->
when (checkedId) {
R.id.dampingRatioHigh -> springForce.dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
R.id.dampingRatioMedium -> springForce.dampingRatio = SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY
R.id.dampingRatioLow -> springForce.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY
R.id.dampingRatioNo -> springForce.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
}
}
stiffnessGroup.setOnCheckedChangeListener { group, checkedId ->
when (checkedId) {
R.id.stiffnessHigh -> springForce.stiffness = SpringForce.STIFFNESS_HIGH
R.id.stiffnesMedium -> springForce.stiffness = SpringForce.STIFFNESS_MEDIUM
R.id.stiffnesLow -> springForce.stiffness = SpringForce.STIFFNESS_LOW
R.id.stiffnesVeryLow -> springForce.stiffness = SpringForce.STIFFNESS_VERY_LOW
}
}
xSpringAnimation = SpringAnimation(ivImg, DynamicAnimation.TRANSLATION_X).setSpring(springForce)
ySpringAnimation = SpringAnimation(ivImg, DynamicAnimation.TRANSLATION_Y).setSpring(springForce)
ivImg.setOnTouchListener { v, event ->
val actionCode = event.action
if (actionCode == MotionEvent.ACTION_DOWN) {
xDiffLeft = event.rawX - ivImg.x
yDiffTop = event.rawY - ivImg.y
xSpringAnimation.cancel()
ySpringAnimation.cancel()
} else if (actionCode == MotionEvent.ACTION_MOVE) {
ivImg.x = event.rawX - xDiffLeft!!
ivImg.y = event.rawY - yDiffTop!!
} else if (actionCode == MotionEvent.ACTION_UP) {
xSpringAnimation.start()
ySpringAnimation.start()
}
true
}
}
}
複製程式碼
自定義屬性
可以動畫的不止DynamicAnimation中定義的一些屬性,下面的例子,定義了scale的屬性,起始就是將scaleX和scaleY進行了整合,程式碼如下:
SpringAnimation(it, object : FloatPropertyCompat<View>("scale") {
override fun setValue(view: View?, scale: Float) {
view!!.scaleX = scale
view!!.scaleY = scale
}
override fun getValue(view: View?): Float {
return view!!.scaleX
}
}).setSpring(SpringForce(2f)
.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY)
.setStiffness(SpringForce.STIFFNESS_LOW))
.setMinimumVisibleChange(0.05f)
.start()
複製程式碼
需要呼叫setMinimumVisibleChange()方法,設定最小可見變化,不然沒有震盪的效果。
關於setMinimumVisibleChange()的原則,參考https://developer.android.com/guide/topics/graphics/fling-animation?hl=zh-cn#setting-minimum-visible-change
效果如下:
var changed = false
val sForce = SpringForce()
.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY)
.setStiffness(SpringForce.STIFFNESS_LOW)
val propertyCompat = object : FloatPropertyCompat<View>("scale") {
override fun setValue(view: View?, scale: Float) {
view!!.scaleX = scale
view!!.scaleY = scale
}
override fun getValue(view: View?): Float {
return view!!.scaleX
}
}
ivImg2.setOnClickListener {
if (!changed) {
SpringAnimation(it, propertyCompat).setSpring(sForce.setFinalPosition(2f))
.setMinimumVisibleChange(0.00390625f)
.start()
} else {
SpringAnimation(it, propertyCompat).setSpring(sForce.setFinalPosition(1f))
.setMinimumVisibleChange(0.00390625f)
.start()
}
changed = !changed
}
複製程式碼
Chained Spring效果
曾經做過一個需求,點選發布按鈕,彈出幾個釋出選項,有一個彈簧效果,下面仿寫了這個效果,如下圖:
實現主要是通過addUpdateListener()以及startToFinalPosition()實現的。
程式碼如下:
class ChainedSpringActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chained_spring)
val springForce = SpringForce(-600f).apply {
dampingRatio = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
stiffness = SpringForce.STIFFNESS_LOW
}
val tvTextSpringAnimation = SpringAnimation(tvPublishText,
DynamicAnimation.TRANSLATION_Y)
val tvVideoSpringAnimation = SpringAnimation(tvPublishVideo,
DynamicAnimation.TRANSLATION_Y).apply {
addUpdateListener { animation, value, velocity ->
tvTextSpringAnimation.animateToFinalPosition(value)
}
}
val tvPicSpringAnimation = SpringAnimation(tvPublishPic,
DynamicAnimation.TRANSLATION_Y).apply {
spring = springForce
addUpdateListener { dynamicAnimation, value, velocity ->
tvVideoSpringAnimation.animateToFinalPosition(value)
}
}
fab.setOnClickListener {
tvPicSpringAnimation.start()
}
}
}
複製程式碼
取消動畫
- cancel():立即停止動畫
- skipToEnd():恢復到最終位置並停止動畫。需要注意的是,在無阻尼的情況下,不能呼叫該方法,為了安全,可以先呼叫canSkipToEnd()進行判斷,有阻尼的情況下返回true,否則返回false
一般來說,skipToEnd()會有跳躍的效果。
總結
SpringAnimation主要是通過設定SpringForce進行動畫的控制,SpringForce的DampingRatio和Stiffness分別表示阻尼係數和生硬度,DampingRatio越大,反彈次數越少,Sniffness越大,達到最終位置的時間就越短。
參考文章
- developer.android.com/guide/topic…
- www.jianshu.com/p/46b1cdc25…
- proandroiddev.com/introductio…
- medium.com/@temidjoy/a…
關注我的技術公眾號,不定期會有技術文章推送,不敢說優質,但至少是我自己的學習心得。微信掃一掃下方二維碼即可關注: