最近在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
若是有什么好的建议欢迎评论指正。