爲什麼我不用ViewPager或RecyclerView來做上下滑切換

上下滑切換翻頁大概是這樣的效果:

webp

slidablelayout

目前網上有諸多如 “仿抖音上下滑...” “仿花椒映客直播...”  之類的技術分享,都有講述實現上下滑切換頁面的方案,其中以 ViewPagerRecyclerView + SnapHelper 兩種方案爲多,但是都有明顯的缺點。以下是一些個人的看法:

爲什麼ViewPager不合適

ViewPager 自帶的滑動效果完全滿足場景,而且支持 FragmentView 等UI綁定,只要對佈局和觸摸事件部分作一些修改,就可以把橫向的 ViewPager 改成豎向。

但是沒有複用是個最致命的問題。在 onLayout 方法中,所有子View會實例化並一字排開在佈局上。當Item數量很大時,將會是很大的性能浪費。

其次是可見性判斷的問題。很多人會以爲 FragmentonResume 的時候就是可見的,而 ViewPager 中的 Fragment 就是個反例,尤其是多個 ViewPager 嵌套時,會同時有多個父 Fragment 多個子 Fragment 處於 onResume 的狀態,卻只有其中一個是可見的。除非放棄 ViewPager 的預加載機制。在頁面內容曝光等重要的數據上報時,就需要判斷很多條件:onResumedsetUserVisibleHintsetOnPageChangeListener 等。

最後是嵌套滑動的問題。同向嵌套滑動是很常見的場景,Google 新出的滑動佈局基本都使用 NestedScrolling 機制來解決嵌套滑動。但是 ViewPager 依然需要開發者自己來處理複雜的滑動衝突。

爲什麼RecyclerView不合適

RecyclerView + SnapHelper 的方案比 ViewPager 好得多,既有對 View 的複用,滑動事件也已經處理好。

但是依然無法雙向無限滑動。我們可以在 getItemCount 方法中返回 Integer.MAX_VALUE 來假裝無限個滑動元素。但是爲了從頭開始就可以下拉滑到上一個,元素列表的索引就不能初始化爲0,那初始值爲 Integer.MAX_VALUE/2 ?
無論怎麼掩飾,理論上還是有滑動到頭的一天。

更優的一種解決方案

使用兩個 View 輪流切換就能完成上下滑的場景。這種方案也有APP在用,但是網上幾乎找不到源碼。因此我把它抽成獨立的庫放在Github倉庫:致力於打造通用、易用和流暢的上下滑動翻頁佈局SlidableLayout

SlidableLayout 本質是一個包含兩個相同大小子 ViewFrameLayout 。兩個子 View 分別作爲 TopViewBackView

靜止狀態下,用戶只會看見 TopView ,而 BackView 被移除或隱藏。

手指向上拖動時, TopView 在y軸上向上偏移, BackView 開始出現,而且 BackView 的頂部與 TopView 的底部相接。

手指向上拖動一定距離後放手,TopView 繼續在y軸上做動畫直到完全消失, BackView 向上直到完全出現。然後 TopViewBackView 互換身份,原來的 BackView 成爲現在的 TopView ,原來的 TopView 被移除或隱藏,成爲下一次滑動的 BackView 。互換後完成一次滑動。

反之,手指向下滑動亦然。

同時要考慮手指放手後,滑動距離不夠或者速度不夠時,TopView 會沿着y軸回彈到原來的位置。 BackView 也跟着原路返回,直到被移除或隱藏。

SlidableLayout 還實現了 NestedScrollingChild 接口,使其能夠與自定義的下拉刷新佈局嵌套滑動。

源碼和使用例子參照 https://github.com/YvesCheung/SlidableLayout 。如有不同意的地方,請在 Github 留下 Issue

推薦閱讀:阿里騰訊Android開發十年,到中年危機就只剩下這套移動架構體系了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章