Android开源控件InboxRecyclerView,支持点击展开(Click-to-expand),下拉折叠(Pull-to-dismiss)的导航效果...

前言

本文原作者 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传送门)

总而言之,千山万水总是情,点个赞再走呗。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值