前言
2020年後第一篇,來點輕鬆的話題吧。在家辦公, UI美眉心血來潮要搞一個滑動特效。 ViewPager+TabLayout ,老生常談的東西了。 ViewPager 是基礎的滑動切換控件, TabLayout 是 和 ViewPager配合使用的標題欄部分(但是 TabLayout也可以脫離ViewPager 獨立使用). 根據查到的資料顯示,谷歌工程師在 ViewPager創立之時,就給風騷的動畫特效預留了接口,我們可以很方便地去使用這個接口進行動畫編程,但是 TabLayout就比較悲情,不但動畫沒預留接口,甚至一些常規操作的接口都沒有提供,所以網上也出現了一些人按照 原 TabLayout的代碼,自己去創造新的xxTabLayout控件。
本文將提供 ViewPager+TabLayout 的實例效果,開發思路 ,以及Demo ****github工程。有興趣的童鞋們希望可以留言多多交流。
Demo地址:https://github.com/18598925736/StudyTabLayout/tree/hank_v1
正文大綱
- 參考效果
- 前置技能
- 實現思路
- 關鍵代碼
- 思維拓展
承接前篇。
關鍵代碼
有了思路,那麼IT民工現在開始搬磚。
一,動畫拆分各個擊破
1) 子view重疊排布
原本的子view都是橫向,從左到右排布,默認的排布方式並沒有相互覆蓋,所以我們可以考慮使用視圖動畫.
(****為什麼是視圖動畫,而不是屬性動畫?因為沒必要,當前的需求我只需要視覺效果上的位置變化,不需要子view的交互事件,用屬性動畫理論上應該也可以,但是直覺會存在交互問題,有時間再試試****)
使用視圖動畫,將所有子view層疊在一起。原本都是橫向排布,所以只需要將所有的view進行x軸位移,即可。
上代碼:
公式的推導很簡單,就是讓右邊的子view向左平移 -position個自身寬度。
效果為:
滑動之後,不再出現其他子view。
2) 讓多個子view之間呈現x軸上的位置差
雖然重疊在了一起,但是我還需要讓右邊的子view呈現位置偏差。並且,越往右偏差越大。
上代碼:
效果:
3) 讓多個子view之間呈現縮放差
x軸上的位置差雖然有了,但是原圖上,越往右越小,所以還需要做出x,y方向上的縮放
上代碼:
效果:
4) 監聽滑動position,做出透明度逐漸變化
視覺效果都有了,那麼可以開始做動畫效果。
經過對position的觀察,我們知道position會以小數的形式漸變。原圖中,向左滑出的view,會以一個透明度慢慢減小的方式消失,那麼先來完成這一步> 。
效果:
5) 監聽滑動position,做出左滑時 當前view的平移動畫
最後一步,滑出消失的view雖然透明度的動畫完成了,但是原圖中,還有一個漸漸向左移動的動畫。
上代碼:
效果:
最終效果和原圖差不多。
二,聲明幾個坑
如果有人按照我的思路去實現上面的效果,很有可能失敗,因為其中幾個坑。
1.ViewGroup.clipChildren屬性
任何一個 ViewGroup的子類都具備的屬性,它的作用是,決定是否消減掉 子view超出自身繪製範圍的部分。
意思就是說,子view的繪製範圍其實是無限大的,但是它能顯示的範圍由父 viewGroup決定,這個屬性為true,父view不允許子view超出自身的部分顯示出來,反之,則是允許超出。這個屬性默認是 true。所以,如果發現 上述效果中某些部分顯示不出來,就要看看 ViewPager(它是一個 ViewGroup)的 clipChildren屬性是否為 true,如果是 true,設置成 false試試。如果還是不行,看看 ViewPager的父容器 的 clipChildren屬性是否為 false。以此類推。
2.ViewPager.setPageTranformer(booleanreverseDrawingOrder,PageTransformertransformer) 方法有兩個參數,第一個是 bool值,它能決定子view的繪製順序。如果按照上述思路實現效果發現,是右邊的子view覆蓋了左邊的子view,那麼就要看看是不是這個值是不是true。如果不是ture,改成true再嘗試。
3.第2點中,如果不想把 reverseDrawingOrder 設置為 true,也有辦法解決。 androidView體系中存在一個 z軸概念, z值越大,就越在上層,其實,也可以使用改變子 view, z屬性的辦法來解決覆蓋效果錯誤的問題。(但是Z軸的設置與版本有關,要區分設備版本,不然低版本上可能程序崩潰)
思維拓展
還記得前文講過的麼,拿到了View之後,再根據滑動時的參數變化,我們幾乎可以對它為所欲為,那麼我們能做的,就不僅僅是 本次的目標效果,像是類似這種滑動特效,還有很多風騷的操作可以玩。像是:
沒有做不到,只有想不到。想到之後,最終能做成什麼效果,就要看自己的數學造詣夠不夠高了。
這次研究最大的收穫,並不是知道了pageTransformer這個接口,而是一種解耦的編程思維,比如我們希望給一個View控件加特效,可以直接在,原本View控件裡面去修改代碼,重寫onTouchEvent來響應滑動事件,或者重寫draw/onDraw進行另外的繪製,用這種方法,無論怎麼做,都已經在對原View進行侵入式的變動,這種方法不到萬不得已,不想用,因為一不小心改出連鎖反應的bug,導致原來的某些特性都受到影響,得不償失。
但是谷歌ViewPager提供了一個另外的思路,將內部View對象,以及view的相關參數通過接口的形式開放給外界,讓編程者可以不再需要關心原本View的內部實現,而直接專心做自己的特效,符合編程的開閉法則,即保證了原代碼的安全,又讓新的特效代碼與原View代碼沒有直接關聯。這是一種優雅,安全又高效的編程方式!
結語
至此,ViewPager部分結束。做出這個效果的基本思路和詳細過程都已經呈上。
再次給出Demo地址:https://github.com/18598925736/StudyTabLayout/tree/hank_v1
此Demo不僅僅是針對ViewPager的滑動特效,還包含了TabLayout 呈現效果的完全自定義。至於TabLayout如何隨心所欲的操縱,下一篇文章將會詳解。先預告一個最終效果圖, 文章會盡快出爐。