Android開源控件InboxRecyclerView,支持點擊展開(Click-to-expand),下拉摺疊(Pull-to-dismiss)的導航效果

前言

本文原做者 Saket Narayan,文章翻譯自做者我的博客 Introducing InboxRecyclerView, a library for building expandable descendant navigation。項目Github傳送門html

正文

簡介

InboxRecyclerView是一款基於RecyclerView的開源控件,支持點擊時展開以及下拉摺疊的動畫切換效果。 java

inboxRecyclerView.gif

若是你有興趣瞭解InboxRecyclerView的工做原理感興趣,下文將對項目的一些細節進行描述。android

Click to Expand

InboxRecyclerView包含主要兩部分:列表項的InboxRecyclerView以及用於顯示可擴展內容的ExpandablePageLayout。單擊某個項目時InboxRecyclerView將執行三個步驟:git

1. 準備展開 InboxRecyclerView將詳細內容與列表項對齊。在展開的過程當中,列表項(ListItem)和內容項(Content)同時進行淡出淡如操做,使列表項看起來自身正在展開。 github

align_content_with_item_on_click.gif

val itemLocation: Rect = captureViewLocation(clickedItem)
contentPage.visibility = View.VISIBLE
contentPage.translationY = itemLocation.y
contentPage.setDimensions(itemLocation.width, itemLocation.height)
複製代碼

此時,該列表項的詳細內容將被加載入ExpandablePageLayout中,具體內容請參考示例程序ide

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內實現,固然,展開動畫支持自定義。 ui

animate_list_items.gif

Pull to Collapse

Pull to Collapse的手勢動做利用了Android View的特性:ViewGroup能夠先於子View攔截觸摸事件,詳細的內容請參考做者的另外一篇文章:Designing a flick dismissible image viewer(計劃會在以後翻譯)。 spa

pull_to_collapse_2.gif
當垂直手勢被檢測到的時候,頁面將隨着手勢滑動。有趣的是,頁面並無隨着用戶手指同步移動,做者在頁面滑動的過程當中增長了一個摩擦力:

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()
      }
    }
  }
}
複製代碼

一旦頁面滾動超出了它的移動範圍,這個摩擦力將會變得很是大,從而產生以下效果: 翻譯

pull_to_collapse_friction.gif

if (isEligibleForCollapse()) {
  val extraFriction = collapseDistanceThreshold / view.translationY
  deltaYWithFriction *= extraFriction
}
複製代碼

InboxRecyclerView用白色覆蓋了ListView的不可見部分,在下拉摺疊的過程當中,這層白色會逐漸淡出以顯示被覆蓋的內容,從而強調了下拉的動畫效果。

background_tint_2.gif
使用這個,App能夠變得很是有創意。好比 Dank,使用狀態欄去指示內容是否可摺疊。

dank_status_bar_tint.gif

總結

這是我翻譯的第一篇有關開源控件的博客,但願各位喜歡。

若是對個人文章感興趣,請移駕輕量級自定義NumberPicker(給我個星吧求求大家了,Github傳送門)

總而言之,千山萬水老是情,點個贊再走唄。

相關文章
相關標籤/搜索