歡迎轉載,但請務必<code>注明出處</code>!http://ryanhoo.github.io/blog/2014/07/16/step-by-step-implement-parallax-animation-for-splash-screen-of-zhihu/
<code>parallax scrolling(視差滾動)</code>,是一種常見的動畫效果。視差一詞來源于天文學,但在日常生活中也有它的身影。在疾馳的動車上看風景時,會發現越是離得近的,相對運動速度越快,而遠處的山川河流隻是緩慢的移動着,這就是最常見的視差效果。視差動畫獨有的層次感能帶來極為逼真的視覺體驗,ios、android
launcher、website都将視差動畫作為提升使用者視覺愉悅度的不二選擇。
用戶端應用第一次打開出現引導頁也不是什麼新鮮的事兒,<code>viewpager</code>配上幾張設計師精心繪制的圖檔,分分鐘即可了事。但是總有人把平凡的事情做到不平凡,如本文的知乎用戶端,亦或是新浪微網誌賀歲版,百度貼吧某版等衆多應用裡都出現了視差動畫的身影,随着使用者手指的滑動,回報以靈動、貼近真實的視覺以及操作體驗,對應用的初始印象登時被提升到一個極高的點。
給我印象最深的是去年新浪微網誌的賀歲版,引導頁是一系列的年畫,裡面有紅色剪紙的小孩兒,滑動界面的時候感覺這些元素在『動』,是真正的靈動,能勾起人童年的回憶,年味兒十足。不過話說我年怎麼過跟新浪微網誌一毛錢關系都沒有,但是這個啟動頁卻是深得我意。隻是這個版本的微網誌找不到了,正好前兩天看到知乎的啟動頁做的也不錯,就正好拿來練練手吧。
本文就知乎android用戶端啟動頁面為例,教你如何實作視差滾動效果。
細心把玩下知乎的啟動頁,不難分析出來,視差動畫主要展現在背景層漸變、内容層元素差異滾動上,動畫内容分别是:
内容:元素差異滾動,形成視差效果(*)
背景:随着界面的滑動,顔色由深藍色漸變為淺藍色(*)
文字:底部提示文案會随頁面變動而切換,有簡單的淡入淡出效果
界面動畫:界面打開,元素的出場動畫(第一頁以及最後一頁)
鑒于其它幾項比較簡單,本文主要講視差動畫以及背景漸變的實作,其它幾項請自行參閱代碼,見後文。
這裡的視差滾動效果,主要表現為内容元素滾動速率的差異上。比如在<code>viewpager</code>中滑動了<code>1px</code>,而a元素移動<code>2px</code>,b元素移動<code>1.5px</code>,這種移動差距的比率,我稱之為<code>parallaxcofficient</code>,即視差系數或者視差速率,正是同一個界面中的元素,由于層級不同,賦予的視差系數不同,在移動速度上的差異形成了視差的錯覺,這就是我們要追求的效果。
那知道原理就好辦了,使用<code>viewpager.onpagechangelistener</code>,動态計算不就得了。no no no! 後面完成背景漸變效果确實需要計算這個,但是<code>viewpager</code>已經為我們準備好了變形元素transformium: <code>viewpager.pagetransformer</code>,它有一個抽象方法<code>transformpage(view page, float position)</code>,正是為我們完成視差動畫量身定制的。
pagetransformer在<code>viewpager</code>滑動時被觸發,它為我們自定義頁面中進行視圖變換打開了一扇大門。
在<code>viewpager</code>源碼中,我們可以很直覺的看到它的調用過程:
從上面的代碼中,不難看出,<code>page</code>就是目前被滑動的頁面,調試得知,每一個child view被<code>nosavestateframelayout</code>包裝,也就是說<code>page.getchildat(0)</code>即是每個<code>page</code>實際的child
view。
<code>position</code>這個參數不看代碼或者文檔,總會誤以為就是我們熟知的<code>integer position</code>,不過它實際上是滑動頁面的一個相對比例,本質跟 1、2、3、4 這種<code>position</code>是一樣的。
比如知乎啟動頁共有6個頁面,分别是a,b,c,d,e,f初始狀态也就是a頁面靜止時,a頁面的<code>position</code>正好是0,b頁面是1。而後滑動頁面(b
-> a),在這個過程中a的<code>position</code>是間于<code>[-1, 0]</code>,b頁面則是間于<code>[0, 1]</code>。
不過這個參數的文檔卻是簡單不夠直覺,對照上面的例子,現在應該很清晰了。
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.
根據上面的分析,我們可以得出一個相對簡單的自定義transformer,對<code>page view</code>進行周遊,遞增或者遞減其<code>parallaxcofficient</code>,以得到我們預期的效果,具體的系數設定請參考代碼。
留心才會發現,從第一頁滑動到最後一頁,背景色會平滑的從深藍色過度到淺藍色,這種效果又該怎麼實作呢?
用過<code>property animation</code>的同學應該知道,以前的<code>animation</code>隻能用在view上,而<code>property animation</code>卻可以用在任意類型屬性值上,這歸功于<code>typeevaluator</code>。
正好我們有<code>argbevaluator</code>,它可以估算兩個顔色值之間,任意部分的色值。是以,隻需要指定起始色值以及最終的色值,傳入滑動所對應的<code>fraction</code>即目前位置相對總距離的比例值,即可獲得相應的色值。
當然,前面說到需要使用<code>viewpager.onpagechangelistener</code>的:
代碼已經push到github了,諸位自取。不過請注意,其素材均取自于知乎android用戶端(你懂的),學習交流即可,請勿用作商業用途。
還求更優雅的實作方式,歡迎發起<code>pull request</code>。
zhihu-parallax-animation
using parallax for fun
and profit
視差滾動(parallax scrolling)效果的原理和實作