歡迎轉載,但請務必註明出處!
前言
Parallax Scrolling (視差滾動)
,是一種常見的動畫效果。視差一詞來源於天文學,但在日常生活中也有它的身影。在疾馳的動車上看風景時,會發現越是離得近的,相對運動速度越快,而遠處的山川河流只是緩慢的移動著,這就是最常見的視差效果。視差動畫獨有的層次感能帶來極為逼真的視覺體驗,iOS、Android
Launcher、Website 都將視差動畫作為提升使用者視覺愉悅度的不二選擇。
客戶端應用第一次開啟出現引導頁也不是什麼新鮮的事兒,ViewPager
配上幾張設計師精心繪製的圖片,分分鐘即可了事。但是總有人把平凡的事情做到不平凡,如本文的知乎客戶端,亦或是新浪微博賀歲版,百度貼吧某版等眾多應用裡都出現了視差動畫的身影,隨著使用者手指的滑動,反饋以靈動、貼近真實的視覺以及操作體驗,對應用的初始印象登時被提升到一個極高的點。
給我印象最深的是去年新浪微博的賀歲版,引導頁是一系列的年畫,裡面有紅色剪紙的小孩兒,滑動介面的時候感覺這些元素在『動』,是真正的靈動,能勾起人童年的回憶,年味兒十足。不過話說我年怎麼過跟新浪微博一毛錢關係都沒有,但是這個啟動頁卻是深得我意。只是這個版本的微博找不到了,正好前兩天看到知乎的啟動頁做的也不錯,就正好拿來練練手吧。
本文就知乎 Android 客戶端啟動頁面為例,教你如何實現視差滾動效果。
介面分析
細心把玩下知乎的啟動頁,不難分析出來,視差動畫主要體現在背景層漸變、內容層元素差異滾動上,動畫內容分別是:
- 內容:元素差異滾動,形成視差效果(*)
- 背景:隨著介面的滑動,顏色由深藍色漸變為淺藍色(*)
- 文字:底部提示文案會隨頁面變動而切換,有簡單的淡入淡出效果
- 介面動畫:介面開啟,元素的出場動畫(第一頁以及最後一頁)
鑑於其它幾項比較簡單,本文主要講視差動畫以及背景漸變的實現,其它幾項請自行參閱程式碼,見後文。
Parallax Scrolling
這裡的視差滾動效果,主要表現為內容元素滾動速率的差異上。比如在 ViewPager
中滑動了 1px
,而 A 元素移動 2px
, B 元素移動 1.5px
,這種移動差距的比率,我稱之為 parallaxCofficient
,即 視差係數 或者 視差速率 ,正是同一個介面中的元素,由於層級不同,賦予的視差係數不同,在移動速度上的差異形成了視差的錯覺,這就是我們要追求的效果。
那知道原理就好辦了,使用 ViewPager.OnPageChangeListener
,動態計算不就得了。
no no no ! 後面完成背景漸變效果確實需要計算這個,但是 ViewPager
已經為我們準備好了變形元素 transformium : ViewPager.PageTransformer
,它有一個抽象方法transformPage(View
page, float position)
,正是為我們完成視差動畫量身定製的。
ViewPager.PageTransformer
PageTransformer 在 ViewPager
滑動時被觸發,它為我們自定義頁面中進行檢視變換開啟了一扇大門。
1
|
|
在 ViewPager
原始碼中,我們可以很直觀的看到它的呼叫過程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Param 1: View page
從上面的程式碼中,不難看出,page
就是當前被滑動的頁面,除錯得知,每一個 child
view 被 NoSaveStateFrameLayout
包裝,也就是說 page.getChildAt(0)
即是每個 page
實際的 child
view 。
Param 2: float position
position
這個引數不看程式碼或者文件,總會誤以為就是我們熟知的 integer
position
,不過它實際上是滑動頁面的一個相對比例,本質跟 1、2、3、4 這種 position
是一樣的。
比如知乎啟動頁共有 6 個頁面,分別是 A、B、C、D、E、F 初始狀態也就是 A 頁面靜止時,A 頁面的 position
正好是 0 ,B 頁面是 1。而後滑動頁面(B
-> A),在這個過程中 A 的 position
是間於 [-1,
0]
,B 頁面則是間於 [0,
1]
。
不過這個引數的文件卻是簡單不夠直觀,對照上面的例子,現在應該很清晰了。
Position of page relative to the current front-and-center position of the pager. 0 is front and center. 1 is one full page position to the right, and -1 is one page position to the left.
ParallaxTransformer
根據上面的分析,我們可以得出一個相對簡單的自定義 transformer ,對 page
view
進行遍歷,遞增或者遞減其parallaxCofficient
,以得到我們預期的效果,具體的係數設定請參考程式碼。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
背景漸變
留心才會發現,從第一頁滑動到最後一頁,背景色會平滑的從深藍色過度到淺藍色,這種效果又該怎麼實現呢?
用過 Property Animation
的同學應該知道,以前的 Animation
只能用在 View 上,而 Property
Animation
卻可以用在任意型別屬性值上,這歸功於 TypeEvaluator
。
正好我們有 ArgbEvaluator
,它可以估算兩個顏色值之間,任意部分的色值。因此,只需要指定起始色值以及最終的色值,傳入滑動所對應的 fraction
即當前位置相對總距離的比例值,即可獲得相應的色值。
1 2 3 4 5 6 |
|
當然,前面說到需要使用 ViewPager.OnPageChangeListener
的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
原始碼
程式碼已經 push 到 Github 了,諸位自取。不過請注意,其素材均取自於知乎 Android 客戶端(你懂的),學習交流即可,請勿用作商業用途。
還求更優雅的實現方式,歡迎發起 pull request
。