最近在Google官方的github庫,看到了一個有意思的recyclerView效果。android
像這樣:git
我的感受彷佛和QQ的效果差很少,只不過QQ用的是Fling動畫,而這裏用的是Spring動畫。有意思的是,彷佛關於實現該效果所使用的EdgeEffectFactory這個類網上博客介紹很少,正好看其API比較簡單,因而打算寫篇博客來介紹這個動畫的實現效果。github
EdgeEffectFactory是存在於Recyclerview的內部的一個靜態類,便可以經過RecyclerView.EdgeEffectFactory
獲得,官方解釋這個類的做用是讓你自定義RecyclerView的過分邊緣滾動的效果
,看上面的gif能夠知道,確實是實現了一個自定義的過分邊緣滾動效果。ide
咱們須要建立一個EdgeEffectFactory並重寫其createEdgeEffect方法,在createEdgeEffect中須要返回一個EdgeEffect對象函數
就像這樣:動畫
上面說到了咱們要給createEdgeEffect中返回一個EdgeEffect對象,那麼這個EdgeEffect類是什麼東東?spa
Android官網說這個類用做:「當用戶滾動到2D空間中的內容邊界以外時,此類將執行可滾動窗口小部件邊緣使用的圖形效果。 」3d
大致能夠理解爲過分邊緣滾動效果的具體實現code
咱們須要重寫這個類中的onPull(deltaDistance: Float)
,onPull(deltaDistance: Float, displacement: Float)
,onRelease()
和onAbsorb
方法。這四個方法(實際上是3個)的調用時機很是好理解。cdn
onPull調用時機就是在用戶朝遠離邊緣的方向拉動的時候,咱們須要在這個方法裏面去更新recyclerView的每個可見item的translationY
值
onRelease調用時機就是在用戶放開的手指的那一刻,咱們須要在這裏讓recyclerView的每個可見item的translationY值變成0,爲了實現一個translationY之間的過渡,咱們可使用屬性動畫,使用SpringAnimation或者FlingAnimation。示例使用的是SpringAnimation(彈簧動畫)。
onAbsorb的調用時機就是recyclerView在脫離用戶手指滑動期間,到了recyclerview的邊緣而且此時速度不爲0。咱們須要在這裏使用一個SpringAnimation或着FlingAnimation來作一個相似「緩衝」的效果
val edgeEffectFactory = object : RecyclerView.EdgeEffectFactory() {
override fun createEdgeEffect(view: RecyclerView, direction: Int): EdgeEffect {
return object : EdgeEffect(view.context) {
override fun onPull(deltaDistance: Float) {
super.onPull(deltaDistance)
handlePull(deltaDistance)
}
override fun onPull(deltaDistance: Float, displacement: Float) {
super.onPull(deltaDistance, displacement)
handlePull(deltaDistance)
}
//更新recyclerView的每個可見item的`translationY`值
private fun handlePull(deltaDistance: Float) {
val sign = if (direction == DIRECTION_BOTTOM) -1 else 1
val translationYDelta = sign * view.height * deltaDistance * OVERSCROLL_TRANSLATION_MAGNITUDE
//一個內聯函數,更新每個recyclerview的可見item的translationY值
view.forEachVisibleHolder { holder: CheeseHolder ->
holder.translationY.cancel()
holder.itemView.translationY += translationYDelta
}
}
//在這裏讓recyclerView的每個可見item的translationY值變成0,使用到了SpringAnimation
override fun onRelease() {
super.onRelease()
view.forEachVisibleHolder { holder: CheeseHolder ->
holder.translationY.start()
}
}
//用SpringAnimation來作一個recyclerview的到達邊緣的慣性緩衝效果
override fun onAbsorb(velocity: Int) {
super.onAbsorb(velocity)
val sign = if (direction == DIRECTION_BOTTOM) -1 else 1
val translationVelocity = sign * velocity * FLING_TRANSLATION_MAGNITUDE
view.forEachVisibleHolder { holder: CheeseHolder ->
holder.translationY.setStartVelocity(translationVelocity).start()
}
}
}
}
}
複製代碼
其中的CheeseHolder是一個Recyclerview的ViewHolder,咱們在裏面存有一個SpringAnimation
class CheeseHolder(view: View) : RecyclerView.ViewHolder(view) {
val translationY: SpringAnimation = SpringAnimation(itemView, SpringAnimation.TRANSLATION_Y)
.setSpring(
SpringForce()
.setFinalPosition(0f)
.setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
.setStiffness(SpringForce.STIFFNESS_LOW)
)
...
}
複製代碼
只要經過
recyclerview.edgeEffectFactory = adapter.edgeEffectFactory
複製代碼
至此,就實現了開篇的gif效果。
這篇文章實際上是參考Google官方的Motion庫的代碼。
本身也寫一個實現:github
若是有什麼好的建議歡迎評論指正。