彈簧動(dòng)畫(huà) Spring Animation

UIView Spring Animation API 的時(shí)間曲線初期上升非常快褐奥,到了后半部分速度非常緩慢咖耘,意在使用開(kāi)頭部分劇烈的變化吸引人們的注意力。實(shí)際上從 iOS 7 開(kāi)始撬码,系統(tǒng)的大部分動(dòng)畫(huà)都是這個(gè) API 實(shí)現(xiàn)的儿倒,比如點(diǎn)擊 App/App 文件夾,Navigation Push/Pop呜笑。

Ease in/out 與 Spring 動(dòng)畫(huà)曲線

Your Spring Animations Are Bad(And It’s Probably Apple’s Fault) 這篇文章指出了 UIView Spring Animation API 與真實(shí)的彈簧行為有些許出入夫否,這讓使用這個(gè) API 的動(dòng)畫(huà)效果有點(diǎn)怪異,這篇文章還提供了能夠做到真實(shí)效果的第三方 Spring 動(dòng)畫(huà)庫(kù)叫胁。官方 Spring 動(dòng)畫(huà)里有個(gè)奇怪的參數(shù)是duration凰慈,所有的動(dòng)畫(huà)都有這個(gè)參數(shù),為什么 Spring 動(dòng)畫(huà)有這個(gè)參數(shù)會(huì)奇怪呢驼鹅?因?yàn)檎鎸?shí)的彈簧行為不需要這個(gè)參數(shù)微谓,但是還需要其他幾個(gè)參數(shù),正如 CASpringAnimation 的參數(shù)那樣输钩,當(dāng)所有的物理參數(shù)確定后豺型,時(shí)間就確定了。為何蘋(píng)果不放出真正的彈簧動(dòng)畫(huà) CASpringAnimation买乃,而是這個(gè)簡(jiǎn)化版的 UIView Spring Animation 呢姻氨?蘋(píng)果已經(jīng)大規(guī)模使用了該 API,說(shuō)明這個(gè) API 足夠?qū)嵱眉粞椤5_(kāi)發(fā)者的期待不一樣肴焊,我們需要前联。從實(shí)現(xiàn)交互動(dòng)畫(huà)的角度來(lái)看,Spring 動(dòng)畫(huà)是唯一能夠指定初始速度的動(dòng)畫(huà) API娶眷,如果完全按照真實(shí)的彈簧行為似嗤,Spring 動(dòng)畫(huà)的時(shí)間不可知(需要另行計(jì)算),而且真實(shí)的彈簧也有一段加速過(guò)程届宠,或許這個(gè)動(dòng)畫(huà)應(yīng)該改名叫做子彈動(dòng)畫(huà)双谆,至少我們都認(rèn)為子彈在槍膛中的加速過(guò)程是不算在射程內(nèi)的。我猜測(cè)蘋(píng)果舍棄了部分參數(shù)并強(qiáng)行增加duration是為了方便使用而做出的妥協(xié)席揽,實(shí)際上差不多忘光了中學(xué)物理的我第一次使用 Spring 動(dòng)畫(huà)時(shí)完全不知道怎么設(shè)置參數(shù),使用參數(shù)完善的第三方 Spring 動(dòng)畫(huà)庫(kù)的時(shí)候更是不知所措谓厘,連看 objc.io 的兩位作者手動(dòng)實(shí)現(xiàn)胡克定律都快看得要睡著了幌羞,恩,還是設(shè)定個(gè)時(shí)間使用起來(lái)方便竟稳。

Update: 06/11 大驚喜属桦!官方終于在 iOS 9 中開(kāi)放了彈簧動(dòng)畫(huà)的 API:iOS 9 QuartzCore Changes,更新內(nèi)容見(jiàn)最下方他爸。
我一直很喜歡 Photos 中點(diǎn)開(kāi)相冊(cè)后照片散開(kāi)的效果聂宾,模擬了彈簧的伸縮,效果非常優(yōu)雅诊笤。

Photos Spring Animation

iOS 7 中推出了新的 UIView 動(dòng)畫(huà)接口系谐,可以使用 Spring 效果,接口如下:


UIView 的 Spring 動(dòng)畫(huà)方法

現(xiàn)實(shí)生活中的彈簧在固定一端拉開(kāi)另一端一定距離后放手的自然回彈過(guò)程中讨跟,每一次回彈的距離都比上一次短纪他,表現(xiàn)為一個(gè)振蕩過(guò)程直至最終停止運(yùn)動(dòng),表現(xiàn)影響回彈距離的因素稱之為阻尼系數(shù)晾匠,也就是方法中的dampingRatio 參數(shù)茶袒,取值范圍0~1,阻尼越小凉馆,每次回彈的能量損失就越小薪寓,想象一下,能夠回彈很久澜共;velocity 參數(shù)用來(lái)間接指定彈簧的初始速度向叉。文檔上的描述是這樣,如果你需要視圖移動(dòng)200像素咳胃,且讓它有100像素/秒的初始速度植康,那么該值設(shè)定為0.5;設(shè)置為1的話展懈,表示動(dòng)畫(huà)在1秒內(nèi)完成销睁。那么動(dòng)畫(huà)本身指定的時(shí)間又起什么作用呢供璧?總體而言,dampingRatio 參數(shù)越小冻记,velocity 參數(shù)越大睡毒,視圖表現(xiàn)為劇烈的搖晃。怎么找到 Photos 那種很優(yōu)雅的范呢冗栗?慢慢調(diào)參數(shù)吧演顾。

目前為止,dampingRatio 參數(shù)設(shè)置為0.8隅居,velocity 參數(shù)設(shè)置為10钠至,有點(diǎn)感覺(jué),但在動(dòng)畫(huà)的末尾回彈的感覺(jué)比較僵硬胎源∶蘧基本上 dampingRatio 參數(shù)在0.9以上沒(méi)有什么效果,在0.8以下涕蚤,動(dòng)畫(huà)有點(diǎn)劇烈宪卿,在0.5以下可以稱得上瘋狂了,這是在 velocity 參數(shù)設(shè)置為10的情況下万栅。而在其他的 velocity 參數(shù)情況下佑钾,這個(gè)趨勢(shì)又有點(diǎn)復(fù)雜了。這兩者的相互影響不是線性的烦粒,該使用積分了休溶。這么摸索,總不是那么回事扰她,而且和原生應(yīng)用的效果總是差點(diǎn)邮偎。想起來(lái),前些天瞅到的一篇文章講彈簧動(dòng)畫(huà)的义黎,沒(méi)怎么細(xì)看禾进,因?yàn)闆](méi)有實(shí)踐,不怎么理解廉涕,今天使用了官方的這個(gè)接口泻云,總有點(diǎn)不大對(duì),找出這篇文章看了看狐蜕,才明白宠纯,這是蘋(píng)果的錯(cuò),不厚道层释,不把真正的彈簧動(dòng)畫(huà)類(lèi)放出來(lái)婆瓜,而弄出來(lái)這個(gè)閹割版的,根本沒(méi)法模擬自然的彈簧效果。效果對(duì)比如下:

官方 API 的 Spring 效果
現(xiàn)實(shí)里真實(shí)的 Spring 效果

以上圖片來(lái)自該文章:Your Spring Animations Are Bad And It’s Probably Apple’s Fault廉白「龀酰可以看出官方版本的效果盡管每次回彈路徑都比上一次短,但它設(shè)置了一個(gè)對(duì)稱的回彈猴蹂,所以衰減過(guò)程并不自然院溺。官方放出的 API 還缺乏其他參數(shù),所以怎么調(diào)都是不對(duì)的磅轻。

由于官方不厚道润歉,開(kāi)發(fā)者自己弄了彈簧動(dòng)畫(huà)踏枣,基本上使用關(guān)鍵幀動(dòng)畫(huà) Key Animation 來(lái)實(shí)現(xiàn)的克伊。普通動(dòng)畫(huà)需要設(shè)定動(dòng)畫(huà)的開(kāi)始以及結(jié)束的數(shù)值以及指定動(dòng)畫(huà)時(shí)間以及時(shí)間曲線皮官,而彈簧動(dòng)畫(huà)還有有多項(xiàng)參數(shù)來(lái)調(diào)整,更加復(fù)雜撮躁,要想有很好的效果摹量,得不斷摸索,如果你記得怎么計(jì)算彈簧的振蕩曲線最好不過(guò)了馒胆。

以下是 Your Spring Animations Are Bad And It’s Probably Apple’s Fault 這篇文章推薦的非官方彈簧動(dòng)畫(huà)實(shí)現(xiàn):

  1. JNWSpringAnimation:該庫(kù)還提供了一個(gè) Mac端的工具來(lái)幫助你調(diào)試動(dòng)畫(huà)效果,而不需要你在模擬器或是真機(jī)上不斷編譯凝果、調(diào)整祝迂、編譯了,真是良心器净。
  2. Facebook's pop:這個(gè)我一直沒(méi)機(jī)會(huì)探索過(guò)型雳,不知道來(lái)實(shí)現(xiàn)彈簧效果如何。
  3. RBBAnimation:官方的反編譯版本山害,效果直追官方纠俭,作者說(shuō)的。發(fā)現(xiàn) Demo 里也提供了在 Mac端進(jìn)行參數(shù)調(diào)試的工具浪慌,贊冤荆。
  4. AnimationEngine:特點(diǎn)是像 pop 一樣使用 CADisplayLink 實(shí)現(xiàn)動(dòng)畫(huà)以及提供方便的 Block 接口。

最后权纤,提供一個(gè)非常好的貝塞爾曲線生成網(wǎng)站 cubic bezier easing 用來(lái)制作時(shí)間曲線是很不錯(cuò)的钓简,也是作者推薦的。

使用了下 RBBAnimation汹想,基于其給出的 Spring 動(dòng)畫(huà)的參數(shù)配置來(lái)摸索效果比較容易點(diǎn)外邓。有點(diǎn)需要注意的是,要將動(dòng)畫(huà)的 additive 屬性設(shè)置為 NO古掏,本來(lái)將設(shè)置 additive 屬性為 YES 使 Core Animation 在更新 presentation layer 之前將動(dòng)畫(huà)的值添加到 model layer 中去损话。但這種情況下,可能是性能上跟不上導(dǎo)致 presentation layer 不流暢(最下方的效果)。目前的配置參數(shù)的效果看起來(lái)除了初速度其他的部分和官方的效果還是比較接近的丧枪。

基于例子摸索出來(lái)的最佳配置參數(shù)

RBBAnimation Spring Animation.gif

Failed Spring Animation.gif

當(dāng)然光涂,這個(gè)動(dòng)畫(huà)和 Photos 的版本還有很多差距,主要在細(xì)節(jié)上豪诲。Photos 的這個(gè)動(dòng)畫(huà)是可交互的顶捷,你可以用雙指縮放來(lái)看看發(fā)生了什么,這里涉及到了 ViewController 的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)屎篱。一個(gè)視圖的出現(xiàn)和消失服赎,其動(dòng)畫(huà)的方式應(yīng)該是從哪來(lái)回哪去,Photos 里的動(dòng)畫(huà)細(xì)節(jié)很好交播。我嘗試了下返回時(shí)的動(dòng)畫(huà)重虑,現(xiàn)在連照片原路返回的細(xì)節(jié)都不對(duì)。

Update: 2015/05/18 之前返回點(diǎn)位置總是不對(duì)的原因找到了秦士。首先介紹下原來(lái)的動(dòng)畫(huà)的思路缺厉,點(diǎn)擊一個(gè)相冊(cè) cell 后,push 一個(gè) CollectionViewController隧土,loadView 后播放動(dòng)畫(huà)提针。合適的動(dòng)畫(huà)應(yīng)該是所有的照片從該相冊(cè)的 cell 處出現(xiàn)然后移動(dòng)到正確的位置上,返回的動(dòng)畫(huà)應(yīng)該是個(gè)逆向過(guò)程曹傀。這里我使用 CALayer 的 position 屬性進(jìn)行動(dòng)畫(huà)辐脖,那么動(dòng)畫(huà)開(kāi)始的位置應(yīng)該是相冊(cè) cell 的 center。但是這個(gè) center 是相對(duì)于相冊(cè) cell 所在的 CollectionView皆愉,動(dòng)畫(huà)開(kāi)始的正確位置應(yīng)該是其相對(duì)于屏幕的位置嗜价。怎么得到這個(gè)位置,很簡(jiǎn)單幕庐,cell 的 center 與CollectionView 的 contentOffset 的差值久锥。為什么是這兩個(gè)值的差值,想想 cell 的 layoutAttributes 是怎么計(jì)算的就明白了异剥。

Push 后的動(dòng)畫(huà)由于初始速度快瑟由,基本上看不出動(dòng)畫(huà)的初始位置其實(shí)是有偏差的;但返回的動(dòng)畫(huà)就能清楚看到冤寿,返回點(diǎn)與相冊(cè) cell 的位置有不小的偏差错妖。這個(gè)偏差怎么來(lái)的?從上面的 Gif 里可以看到我開(kāi)啟了 NavigationBar的顯示疚沐,此時(shí) CollectionView 的初始 contentOffset 是(0.0, -44.0)暂氯,因?yàn)?NavigationBar 的高度是44,為了正確顯示內(nèi)容亮蛔,F(xiàn)lowLayout 已經(jīng)自動(dòng)調(diào)校了 CollectionView 的初始 contentOffset痴施,之前我以為是(0,0),所以有偏差。問(wèn)題根源找到辣吃,解決就好辦了动遭,計(jì)算時(shí)加上這個(gè)初始的調(diào)校值即可,返回動(dòng)畫(huà)的位置偏差問(wèn)題解決神得。

Photos 的動(dòng)畫(huà)中還有幾個(gè)好的細(xì)節(jié)厘惦,比如點(diǎn)擊相冊(cè) cell 后,相冊(cè)里的照片的動(dòng)畫(huà)順序應(yīng)該與相冊(cè)上的一致哩簿,展開(kāi)相冊(cè)時(shí)不明顯宵蕉,返回時(shí)這個(gè)動(dòng)作順序就很重要了,要是動(dòng)畫(huà)最后看到的照片與相冊(cè)封面的不一致节榜,就太破壞感覺(jué)了羡玛。我在實(shí)現(xiàn)這個(gè)細(xì)節(jié)時(shí),發(fā)現(xiàn)利用 CollectionView 的 visibleCells得到的 cell 的索引位置并不是按順序來(lái)的宗苍,在使用前必須先排序才行稼稿。還有兩個(gè)細(xì)節(jié)很贊,Photos 里照片收回時(shí)并不是彈簧動(dòng)畫(huà)讳窟,不然影響歸納時(shí)的整齊感让歼;而且還體現(xiàn)了照片與相冊(cè)封面看到的照片的尺寸變化。

這里有一點(diǎn)需要注意丽啡,在viewDidLoad里先將 collectionView 隱藏谋右,在播放動(dòng)畫(huà)時(shí)再將隱藏解除。不這樣的話碌上,就會(huì)出現(xiàn)所有的cell 已經(jīng)處于正確的位置上,然后進(jìn)行了一次從某個(gè)點(diǎn)移動(dòng)到正確位置的動(dòng)畫(huà)浦徊,應(yīng)該只有從某個(gè)點(diǎn)移動(dòng)到正確位置的動(dòng)畫(huà)過(guò)程馏予,然后動(dòng)畫(huà)停止,cell 都在正確的位置上盔性。

關(guān)于 UICollectionView 中的 contentOffset 屬性霞丧,推薦文章: 理解 ScrollView

CASpringAnimation in iOS 9 API:

CASpringAnimation API

好原來(lái)使用的據(jù)說(shuō)是反編譯官方的 RBBAnimation 的參數(shù)套在 CASpringAnimation 身上冕香,感覺(jué)不對(duì)勁蛹尝。Xcode 和在線文檔庫(kù)都無(wú)法查詢到該類(lèi),在線 API 倒是可以查詢到悉尾,但是沒(méi)有任何屬性描述突那,不至于這么偷懶吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末构眯,一起剝皮案震驚了整個(gè)濱河市愕难,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖猫缭,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葱弟,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡猜丹,警方通過(guò)查閱死者的電腦和手機(jī)芝加,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)射窒,“玉大人藏杖,你說(shuō)我怎么就攤上這事÷盅螅” “怎么了制市?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)弊予。 經(jīng)常有香客問(wèn)我祥楣,道長(zhǎng),這世上最難降的妖魔是什么汉柒? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任误褪,我火速辦了婚禮,結(jié)果婚禮上碾褂,老公的妹妹穿的比我還像新娘兽间。我一直安慰自己,他們只是感情好正塌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布嘀略。 她就那樣靜靜地躺著,像睡著了一般乓诽。 火紅的嫁衣襯著肌膚如雪帜羊。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天鸠天,我揣著相機(jī)與錄音讼育,去河邊找鬼。 笑死稠集,一個(gè)胖子當(dāng)著我的面吹牛奶段,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剥纷,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼痹籍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了晦鞋?” 一聲冷哼從身側(cè)響起词裤,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤刺洒,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后吼砂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逆航,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年渔肩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了因俐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡周偎,死狀恐怖抹剩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蓉坎,我是刑警寧澤澳眷,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站蛉艾,受9級(jí)特大地震影響钳踊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜勿侯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一拓瞪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧助琐,春花似錦、人聲如沸兵钮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)掘譬。三九已至泰演,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屁药,已是汗流浹背粥血。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工柏锄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酿箭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓趾娃,卻偏偏與公主長(zhǎng)得像缭嫡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子抬闷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容