Android开源控件InboxRecyclerView,支持点
前言
本文原作者 Saket Narayan,文章翻译自作者个人博客 Introducing InboxRecyclerView, a library for building expandable descendant navigation。项目Github传送门。
正文
简介
InboxRecyclerView是一款基于RecyclerView的开源控件,支持点击时展开以及下拉折叠的动画切换效果。

(如果图片不幸挂了,请打开这里)
如果你有兴趣了解InboxRecyclerView的工作原理感兴趣,下文将对项目的一些细节进行描述。
Click to Expand
InboxRecyclerView包含主要两部分:列表项的InboxRecyclerView
以及用于显示可扩展内容的ExpandablePageLayout
。单击某个项目时InboxRecyclerView将执行三个步骤:
1. 准备展开
InboxRecyclerView将详细内容与列表项对齐。在展开的过程中,列表项(ListItem)和内容项(Content)同时进行淡出淡如操作,使列表项看起来自身正在展开。

val itemLocation: Rect = captureViewLocation(clickedItem)
contentPage.visibility = View.VISIBLE
contentPage.translationY = itemLocation.y
contentPage.setDimensions(itemLocation.width, itemLocation.height)
此时,该列表项的详细内容将被加载入ExpandablePageLayout
中,具体内容请参考示例程序
2. 展开列表项
在对齐列表项和内容项后,下一步是为展开设置动画效果。为了保证展开动画流畅,InboxRecyclerView使用View#setClippedBounds(Rect)对View的可见部分进行动画处理,以营造一种它正在展开的错觉。

fun animateDimensions(toWidth: Int, toHeight: Int) {
val fromWidth = clipBounds.width()
val fromHeight = clipBounds.height()
ObjectAnimator.ofFloat(0F, 1F)
.addUpdateListener {
val scale = it.animatedValue as Float
val newWidth = (toWidth - fromWidth) * scale + fromWidth
val newHeight = (toHeight - fromHeight) * scale + fromHeight)
contentPage.clipBounds = Rect(0, 0, newWidth, newHeight)
}
.start()
}
3.给列表项添加动画效果
为了实现展开内容正在推开其他列表项的动画效果,在动画期间其他项目也会随着被展开的内容同步移动。这在ItemExpandAnimator内实现,当然,展开动画支持自定义。

Pull to Collapse
Pull to Collapse的手势动作利用了Android View的特性:ViewGroup可以先于子View拦截触摸事件,详细的内容请参考作者的另一篇文章:Designing a flick dismissible image viewer(计划会在之后翻译)。

当垂直手势被检测到的时候,页面将随着手势滑动。有趣的是,页面并没有随着用户手指同步移动,作者在页面滑动的过程中增加了一个摩擦力:
override fun onTouch(view, event): Boolean {
when (event.action) {
ACTION_MOVE -> {
val deltaY = event.rawY - lastTouchY
val friction = 4F
var deltaYWithFriction = deltaY / frictionFactor
view.translationY += deltaYWithFriction
val lastTouchY = event.rawY
}
ACTION_UP -> {
if (isEligibleForCollapse()) {
collapsePage()
} else {
smoothlyResetPage()
}
}
}
}
一旦页面滚动超出了它的移动范围,这个摩擦力将会变得非常大,从而产生如下效果:

if (isEligibleForCollapse()) {
val extraFriction = collapseDistanceThreshold / view.translationY
deltaYWithFriction *= extraFriction
}
InboxRecyclerView用白色覆盖了ListView的不可见部分,在下拉折叠的过程中,这层白色会逐渐淡出以显示被覆盖的内容,从而强调了下拉的动画效果。

使用这个,App可以变得非常有创意。比如Dank,使用状态栏去指示内容是否可折叠。

总结
这是我翻译的第一篇有关开源控件的博客,希望各位喜欢。
如果对我的文章感兴趣,请移驾轻量级自定义NumberPicker(给我个星吧求求你们了,Github传送门)
总而言之,千山万水总是情,点个赞再走呗。