動(dòng)畫翻譯3
自然的動(dòng)畫
可以使用標(biāo)準(zhǔn)的時(shí)間曲線瞒渠,但那并不是最優(yōu)方案,并且不一定會(huì)帶給用戶令人贊嘆和愉悅的感覺良蒸,因?yàn)闃?biāo)準(zhǔn)時(shí)間曲線型的動(dòng)畫總會(huì)個(gè)人一種機(jī)械而不流暢的感覺,不像實(shí)際生活中的物件接受到外力所作出的一些反應(yīng)伍玖。
如果我們想要做出真實(shí)自然的動(dòng)畫效果嫩痰,就要探究真實(shí)環(huán)境中物體受到外力時(shí)做出的反應(yīng),然后去模仿物體當(dāng)時(shí)的反應(yīng)窍箍。而這個(gè)正是處理軟件中的動(dòng)畫效果的秘密訣竅串纺。
但是一個(gè)真實(shí)自然的動(dòng)作是什么樣的呢丽旅?哪個(gè)可以作為物體根據(jù)物理法則移動(dòng)的例子呢?
一個(gè)在末端系著一個(gè)物體的彈簧可以很好的說明這個(gè)問題纺棺。它運(yùn)動(dòng)起來(lái)像是你可以預(yù)見的那樣榄笙,因?yàn)槟阒耙呀?jīng)很熟悉末端帶有物體的彈簧的運(yùn)動(dòng)軌跡。它的運(yùn)動(dòng)軌跡和標(biāo)準(zhǔn)的Ease曲線又是很不同的祷蝌,我們看下末端有物體的彈簧的運(yùn)動(dòng)軌跡茅撞。
這些曲線表示的是系在彈簧末端的物體的運(yùn)動(dòng)軌跡,以及彈簧的張力巨朦、摩擦力和質(zhì)量是如何影響這個(gè)運(yùn)動(dòng)軌跡的米丘。
如果仔細(xì)觀察上圖中的黑色線的話,它代表的是有阻尼的系統(tǒng)的運(yùn)動(dòng)軌跡罪郊,它會(huì)在達(dá)到穩(wěn)定狀態(tài)之前來(lái)回的震蕩蠕蚜。這個(gè)阻尼彈簧動(dòng)作能夠使動(dòng)畫具有彈性效果尚洽。例如:這種彈簧的動(dòng)畫效果幾乎貫穿Facebook paper整個(gè)APP中悔橄。
中間的藍(lán)色曲線也代表的是有阻尼的系統(tǒng),但是它更加的平滑腺毫,這種細(xì)微的感覺能夠使你的APP變得更加的熱情洋溢和青春癣疟。
紅色的曲線描繪的是基本沒有彈性的并且只在基本要穩(wěn)定的狀態(tài)下彈射了一下。如果一個(gè)物體基本不擺動(dòng)并且沒有一次彈跳效果潮酒,只是簡(jiǎn)單的緩慢降速達(dá)到最終值睛挚,那么就被成為是過阻尼的。
彈簧效果的動(dòng)畫運(yùn)動(dòng)曲線和easing類型的動(dòng)畫曲線比較相似(因?yàn)樗鼈兌际乔€<崩琛)扎狱,但是它們的實(shí)現(xiàn)機(jī)制是不同的。easing動(dòng)畫曲線是通過定義不同的貝塞爾曲線來(lái)操縱句柄來(lái)影響曲線的形狀的勃教。但是淤击,有許多曲線和波動(dòng)并不能用貝塞爾曲線來(lái)進(jìn)行描述,而其中就包括質(zhì)量——阻尼彈簧系統(tǒng)故源。
這種類型的運(yùn)動(dòng)通常備用來(lái)創(chuàng)作流暢的污抬、彈簧效果的動(dòng)畫,可以通過末端的物體的質(zhì)量绳军、彈簧的張力印机、以及阻尼的大小等來(lái)影響曲線形狀。
- 質(zhì)量 是指系在彈簧末端的物體的質(zhì)量门驾。
- 張力 是指彈簧能夠拉長(zhǎng)多少并且決定于彈簧的厚度和環(huán)繞方式射赛。
- 阻尼或者摩擦力 是指當(dāng)你從水中拔出手或者是想要在水中快走所收到的阻力。
這些都是定義彈簧動(dòng)畫的關(guān)鍵因素奶是。
如果你想自己封裝實(shí)現(xiàn)一些web 楣责、iOS或者是其它平臺(tái)的彈簧效果的動(dòng)畫顷蟆,你就必須了解一些彈簧系統(tǒng)動(dòng)畫背后的一些數(shù)學(xué)原理。而對(duì)于iOS來(lái)說腐魂,已經(jīng)有了一些優(yōu)秀的動(dòng)畫框架(由蘋果公司和其它公司構(gòu)建的)帐偎,可以使用這些現(xiàn)存的框架來(lái)實(shí)現(xiàn)一些流暢自然、彈簧效果動(dòng)畫蛔屹。
當(dāng)我們仔細(xì)觀察一些動(dòng)畫代碼之前削樊,我們應(yīng)該討論一下iOS的界面和動(dòng)畫發(fā)展。
從UIKit & 核心動(dòng)畫開始
從最基本的層面上將兔毒,屏幕上所顯示的控件都屬于UIView類漫贞。他們是矩形的,通過坐標(biāo)系和緯度來(lái)定義他們顯示在屏幕上的位置和尺寸育叁。UIView是UIKit框架中用來(lái)構(gòu)建界面的最基本的迅脐。每一個(gè)View有可能在內(nèi)部繪有文字、形狀豪嗽、圖片等谴蔑。例如,status bar是顯示在屏幕頂部的一條長(zhǎng)的窄的View龟梦,而它內(nèi)部的所有控件(時(shí)間隐锭、電池標(biāo)識(shí)、信號(hào)強(qiáng)度指示等)都是些其他的View计贰。
有一些特殊的UIView是具有獨(dú)特的功能和屬性的钦睡。像UIButton是用來(lái)構(gòu)建界面按鈕的,而UIImageView則是用來(lái)展示圖片的躁倒,UILabel是用來(lái)展示文字信息荞怒,UITableView是用來(lái)展示一些表格數(shù)據(jù)。你也可以自定義一些View用來(lái)展示一些你想展示的任何東西秧秉。
下面是一個(gè)屏幕截屏褐桌,該界面被分解為多個(gè)不同的View。
- 1福贞、carrier圖片View
- 2撩嚼、WiFi信號(hào)強(qiáng)度指示
- 3、當(dāng)前時(shí)間
- 4挖帘、電量指示
- 5完丽、“漢堡包”菜單按鈕
- 6、標(biāo)題欄
- 7拇舀、一個(gè)用來(lái)切換子菜單的按鈕
- 8逻族、一個(gè)* UITableViewCell*的View,用來(lái)顯示UITableView的一行展示的所有元素骄崩。
- 9聘鳞、UILabel展示的標(biāo)題
- 10薄辅、評(píng)論按鈕,包含有評(píng)論的數(shù)目以及一個(gè)表示評(píng)論的氣泡圖
- 11抠璃、顯示轉(zhuǎn)發(fā)URL地址的UILabel
- 12站楚、用UILabel展示的數(shù)據(jù)
如果你對(duì)iOS界面開發(fā)不是很熟悉的話,可以仔細(xì)觀察下自己喜歡的APP搏嗡,看看能不能對(duì)完成的界面進(jìn)行分解窿春,這樣你就可以將他們按照分解的部分進(jìn)行代碼實(shí)現(xiàn)。
UIView承擔(dān)著很多責(zé)任采盒,其中一個(gè)就是需要響應(yīng)外界的事件旧乞。界面里的任何View都可以響應(yīng)外界事件,你也可以定義某些特殊的View能夠響應(yīng)用戶對(duì)他們的點(diǎn)擊事件磅氨。
UIView在本質(zhì)上是一個(gè)包含圖形內(nèi)容的矩形尺栖。處于其他View的上層或者緊挨著其他View,也可能有一些很好的透明的效果烦租。
你可以想象一下延赌,在一個(gè)屏幕上移動(dòng)View是一個(gè)多么大的挑戰(zhàn)。
蘋果公司推出核心動(dòng)畫的原因
核心動(dòng)畫Core Animation是一個(gè)快速有效實(shí)現(xiàn)圖形復(fù)合效果動(dòng)畫框架左权。雖然他的名字里含有animation皮胡,但是如果你認(rèn)為它只能做這些事情,那你就大錯(cuò)特錯(cuò)了赏迟。實(shí)際上,它負(fù)責(zé)將所有的View渲染到屏幕上蠢棱、進(jìn)行快速的透明度計(jì)算锌杀、圖片過濾和可視效果。雖然當(dāng)初是為iOS設(shè)計(jì)的泻仙,但是自從OSX 10.5以后糕再,在Mac平臺(tái)上同樣適用。
為了管理由GPU渲染到屏幕上的圖形內(nèi)容玉转,Core Animation將CALayer作為主力突想。CALayer才是那個(gè)實(shí)實(shí)在在做界面渲染工作的,實(shí)際上究抓,UIView是封裝了CALayer和核心動(dòng)畫猾担,并且在蘋果內(nèi)部稱為“Layer kit”!當(dāng)你操縱屏幕上顯示的View的位置或者維度的時(shí)候刺下,你實(shí)際上是在移動(dòng)它的CALayer绑嘹。核心動(dòng)畫在硬件管理層上合成和操縱你APP界面內(nèi)容的展示,使顯示變得流暢而不卡頓橘茉。iOS所能實(shí)現(xiàn)的動(dòng)畫效果工腋,都是因?yàn)楹诵膭?dòng)畫框架的原因姨丈。
層可以像UIView對(duì)象一樣,存在于界面等級(jí)框架中來(lái)構(gòu)建交互界面擅腰。你可以用CALayer代替UIView對(duì)象來(lái)構(gòu)建交互界面蟋恬,就像將UIView對(duì)象放在一個(gè)父子層級(jí)關(guān)系(superview-subview)中一樣,將CALayer放在父子層的層級(jí)關(guān)系(superlayer-sublayer)中趁冈。
雖然可以完全使用CALayer而不是UIView來(lái)實(shí)現(xiàn)界面搭建筋现,但是大多數(shù)的iOS開發(fā)者并不是直接使用CALayer而是用UIView對(duì)象進(jìn)行搭建,除非需要一次性的處理大量的圖形箱歧。如果你想直接修改View的某些屬性矾飞,你可以在任何時(shí)候取到相對(duì)應(yīng)的layer層,例如呀邢,可以通過操縱CALayer來(lái)設(shè)置一個(gè)View對(duì)象的圓角半徑(corner radius)洒沦。
簡(jiǎn)單動(dòng)畫
是時(shí)候上一部分代碼了。讓我們開始設(shè)置屏幕上一個(gè)View對(duì)象的圓角半徑价淌。因?yàn)槭且粋€(gè)快速簡(jiǎn)單案例的原因申眼,我們將這個(gè)UIView對(duì)象放在main window上,但是如果你是在做一個(gè)真實(shí)的APP的話蝉衣,就需要將這個(gè)View對(duì)象放在管理當(dāng)前屏幕的一個(gè)控制器中括尸。
注意:如果你是剛剛開始接觸iOS開發(fā)和Objective-C,我建議先看一下我寫的對(duì) Obj-C and Cocoa的[介紹]:https://designthencode.com/scratch/病毡,也或者你可以繼續(xù)學(xué)習(xí)濒翻。
UIView *redBall = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
redBall.backgroundColor = [UIColor redColor];
redBall.layer.cornerRadius = 50;
[self.window addSubview:redBall];
我們創(chuàng)建了一個(gè)紅色的UIView對(duì)象,然后通過定義他的X和Y坐標(biāo)以及寬高限制在屏幕上的顯示位置啦膜。我們?cè)O(shè)置它的backgroundColor
為紅色有送。像上面講過的那樣,如果要設(shè)置一個(gè)View對(duì)象的圓角僧家,可以通過View對(duì)象的layer層來(lái)設(shè)置雀摘,所以我們使用layer.cornerRadius
為50(View對(duì)象寬高的一半)。如果你將這段代碼寫在APP的代理文件當(dāng)中-application:didFinishLaunchingWithOptions
方法中八拱,你會(huì)在程序一啟動(dòng)的時(shí)候就看到下面這樣的情形阵赠。
是不是很有意思呢?接下來(lái)我們要給它設(shè)置動(dòng)畫效果了肌稻。
iOS提供了一些產(chǎn)生動(dòng)畫的機(jī)制:給一個(gè)層添加CAAnimation或者使用block來(lái)設(shè)置UIView對(duì)象的動(dòng)畫效果的值清蚀。接下來(lái)我們要通過block方式使UIView對(duì)象的尺寸從原始尺寸變?yōu)樵瓉?lái)尺寸的2倍灯萍。
UIView *redBall = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
redBall.backgroundColor = [UIColor redColor];
redBall.layer.cornerRadius = 50;
[self.window addSubview:redBall];
[UIView animateWithDuration:.5 delay:0
options:UIViewAnimationOptionCurveEaseInOut animations:^{
redBall.transform = CGAffineTransformMakeScale(2.0, 2.0);
} completion:NULL];
這段代碼調(diào)用了+animateWithDuration:delay:options:animations:completion:
這個(gè)UIView對(duì)象提供的一些實(shí)現(xiàn)動(dòng)畫效果方法中的其中一種。第一個(gè)參數(shù):duration設(shè)置為0.5秒旦棉,第二個(gè)參數(shù)delay設(shè)置為0.
這個(gè)options參數(shù)是用來(lái)讓我們選擇動(dòng)畫進(jìn)行的方式的药薯,而對(duì)于本例來(lái)說我們選擇了UIViewAnimationOptionCurveEaseInOut這種效果,而這種效果是一個(gè)簡(jiǎn)單的ease-in-out的時(shí)間曲線救斑。其它的曲線有線性童本、 ease-in 和 ease-out。
接下來(lái)穷娱,我們?cè)赽lock代碼塊中設(shè)置了動(dòng)畫效果最終的狀態(tài)值运沦。核心動(dòng)畫會(huì)自動(dòng)的在當(dāng)前值和最終值之間流暢的修改尺寸的值泵额,產(chǎn)生流暢的動(dòng)畫效果。在這個(gè)案例當(dāng)中携添,我希望動(dòng)畫最終效果是球的尺寸變?yōu)樵瓉?lái)最初尺寸的兩倍嫁盲,所以我設(shè)置了transform
屬性設(shè)置為了一個(gè)新的值,他是一個(gè)矩陣用來(lái)表示如何通過線性代數(shù)方式修改當(dāng)前對(duì)象屬性烈掠。有多種操縱當(dāng)前View對(duì)象的transform
屬性的方法(縮放比例、旋轉(zhuǎn)瘾蛋、位置)等,所以蘋果提供了一系列的函數(shù)來(lái)修改這些你感興趣的值哺哼,我們的例子中就是對(duì)縮放比例進(jìn)行的修改奇唤。設(shè)置transform
屬性為CGAffineTransformMakeScale(2.0, 2.0)
,意味著我們希望除了縮放比例以外的其它屬性值保持不變咬扇,而尺寸則變?yōu)樵瓉?lái)的兩倍廊勃。
因?yàn)槲覀儾⒉幌朐谶@個(gè)動(dòng)畫結(jié)束以后有其它的動(dòng)作,所以我們將完成參數(shù)設(shè)置為NULL坡垫。
如果我們?cè)赽lock代碼塊中修改幾個(gè)View對(duì)象相關(guān)的屬性,那么這個(gè)屬性值會(huì)在動(dòng)畫持續(xù)時(shí)間內(nèi)隨著尺寸大小的改變而改變”疲現(xiàn)在我們?cè)谶@個(gè)代碼塊中繼續(xù)修改一些其它相關(guān)屬性。
UIView *redBall = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
redBall.backgroundColor = [UIColor redColor];
redBall.layer.cornerRadius = 50;
[self.window addSubview:redBall];
[UIView animateWithDuration:.5 delay:0
options:UIViewAnimationOptionCurveEaseInOut animations:^{
redBall.backgroundColor = [UIColor greenColor];
redBall.transform = CGAffineTransformConcat(
CGAffineTransformMakeScale(2.0, 2.0),
CGAffineTransformMakeTranslation(75, 0));
} completion:NULL];
首先皮迟,我們將backgroundColor
的屬性從紅色變?yōu)榫G色。核心動(dòng)畫會(huì)自動(dòng)改變并添加中間顏色伏尼。
接下來(lái),我們改變了View對(duì)象的兩個(gè)transform屬性:它的尺寸和位移燥透。位移就是將View對(duì)象向上辨图、下、左故河、右進(jìn)行移動(dòng)吱韭。在我們的案例當(dāng)中忧勿,我們將View對(duì)象向右移動(dòng)了75.我們使用CGAffineTransformConcat()
函數(shù)將兩個(gè)屬性變化的動(dòng)畫合并成為一個(gè),然后我們可以將一個(gè)單獨(dú)的transform矩陣賦值給這個(gè)View對(duì)象熏挎。
現(xiàn)在理解了嗎晌砾?雖然矩陣轉(zhuǎn)換有點(diǎn)復(fù)雜并且不是太好理解,但是因?yàn)樘O果的整合养匈,所以即使你沒有線性代數(shù)的額背景,也可以實(shí)現(xiàn)很好的動(dòng)畫效果呕乎。改變一個(gè)View對(duì)象的transform矩陣是一個(gè)很好地實(shí)現(xiàn)動(dòng)畫的方法。
iOS7里的彈簧動(dòng)畫
從iOS7開始帝璧,蘋果開始給當(dāng)前的動(dòng)畫系列中添加了彈簧效果動(dòng)畫方法湿刽。實(shí)際上,增加的不僅僅是這些诈闺。UIKit Dynamics
框架是一個(gè)融合了物理原理的,你可以給View對(duì)象添加一些諸如萬(wàn)有引力現(xiàn)象、粘性彈簧效果以及外力的效果刃滓。
我們可以看一下iOS7更新的對(duì)額外參數(shù)實(shí)現(xiàn)彈簧效果的動(dòng)畫代碼塊嗤军。
UIView *redBall = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
redBall.backgroundColor = [UIColor redColor];
redBall.layer.cornerRadius = 50;
[self.window addSubview:redBall];
[UIView animateWithDuration:3 delay:0 usingSpringWithDamping:.3
initialSpringVelocity:0 options:0 animations:^{
redBall.transform = CGAffineTransformMakeTranslation(300, 0);
} completion:NULL];
這是一個(gè)很長(zhǎng)的方法,這里出現(xiàn)了一些我們之前方法中所沒有出現(xiàn)過的參數(shù)叙赚。包括阻尼和初始的彈簧速度。彈簧的阻尼是一個(gè)介于0~1之間的值胧砰,1表示的是過阻尼彈簧系統(tǒng)苇瓣,沒有震蕩效果,0表示的是沒有阻尼的情況击罪,會(huì)出現(xiàn)很多的震蕩效果。速度參數(shù)表示的是物體初始狀態(tài)下運(yùn)動(dòng)的快慢媳禁,這個(gè)效果在配合手勢(shì)使用的時(shí)候是很有用的。
我們例子中囱怕,我們?cè)O(shè)置彈簧阻尼為0.3(一個(gè)合理的值)毫别,速度為0.動(dòng)畫持續(xù)時(shí)間被延長(zhǎng)了,因?yàn)檎鹗幮Ч拇嬖诘夯拢∏蛞ㄒ恍r(shí)間來(lái)平復(fù)。
個(gè)人認(rèn)為齐佳,iOS7提供的方法并沒有按照我認(rèn)為的應(yīng)有的方式來(lái)運(yùn)動(dòng),或者說他們并沒有提供足夠的接口來(lái)改進(jìn)這個(gè)動(dòng)畫效果。當(dāng)你構(gòu)建了一個(gè)Mac APP并且需要這個(gè)UIKit Dynamics
動(dòng)畫的時(shí)候就悲劇了本鸣。如果你的應(yīng)用是iOS7之前的版本呢?因?yàn)槟悴⒉荒茉趇OS7之前的版本中使用這個(gè)動(dòng)畫效果闷煤。
那么我們應(yīng)該如何實(shí)現(xiàn)自然地、彈簧效果的動(dòng)畫呢鲤拿?有么有其它的選擇方案呢?我下面將給大家介紹的方案絕對(duì)算得上是很好的替代方案生音,我對(duì)這兩個(gè)框架有著毫不掩飾的喜歡窒升,并且在之前提交的APP中都是用了這兩個(gè)框架,而且會(huì)在以后繼續(xù)使用饱须。
一個(gè)是 JNWSpringAnimation,一個(gè)是Pop by Facebook。
JNWSpringAnimation
這個(gè)框架是由一個(gè)Mac和iOS開發(fā)者所寫的蓉媳。為了更好地理解為什么它是強(qiáng)大的。我們就不得不再次說說核心動(dòng)畫了减宣。
像之前提到過的那樣号杠,核心動(dòng)畫的時(shí)間曲線是由貝塞爾曲線定義的。在核心動(dòng)畫里姨蟋,你可以設(shè)置線性、ease——in 和ease-in-out or ease-out 悠砚,又或者你可以自主的像在CSS中一樣來(lái)控制貝塞爾曲線的控制點(diǎn)堂飞。
但是灌旧,你并不能通過這種方式來(lái)定義彈簧動(dòng)畫绰筛,因?yàn)樗鼈兊男螤钐^高級(jí)了。那么衡蚂,我們應(yīng)該怎么辦呢?我們能不能創(chuàng)作一個(gè)類似的動(dòng)畫效果呢毛甲?
【動(dòng)畫圖】
除了之前我們所介紹那種復(fù)雜的不好理解的動(dòng)畫效果彻磁,蘋果還為開發(fā)者提供了一個(gè)CAKeyframeAnimation
。
CAKeyframeAnimation動(dòng)畫是一種可以設(shè)置多個(gè)值的一種動(dòng)畫效果七咧,你可以使用它來(lái)實(shí)現(xiàn)復(fù)雜的動(dòng)畫效果,比如控件上一秒在這個(gè)位置辈挂,然后下一秒在下一個(gè)方位裹粤。
JNWSpringAnimation工作的額方式是遥诉,先定義彈簧的阻尼矮锈、張力和質(zhì)量,然后告訴你要進(jìn)行動(dòng)畫的屬性债朵,然后JNWSpringAnimation會(huì)給每一個(gè)部分設(shè)置1/60秒時(shí)間的動(dòng)畫序芦,并最終通過調(diào)用CAKeyframeAnimation來(lái)實(shí)現(xiàn)多個(gè)屬性的動(dòng)畫效果粤咪。你所要做的寥枝,就是給CALayer設(shè)置keyframe動(dòng)畫效果囊拜,核心動(dòng)畫會(huì)一秒鐘遍歷這些60次知道到達(dá)最終值狀態(tài)和動(dòng)畫完成。
讓我們來(lái)看一下如何使用JNWSpringAnimation來(lái)對(duì)不同的屬性實(shí)現(xiàn)不同的彈簧動(dòng)畫效果来吩。我們將對(duì)之前的紅色的球的尺寸從原始變?yōu)樵瓉?lái)的兩倍弟疆,以一種定義好的曲線效果怠苔。
JNWSpringAnimation *scale =
[JNWSpringAnimation animationWithKeyPath:@"transform.scale"];
在一開始仪糖,我們定義一個(gè)JNWSpringAnimation對(duì)象锅劝,一個(gè)新的動(dòng)畫實(shí)例故爵,并且命名為scale。我們把初始化值傳遞給了transform.scale劲室,但是這是什么意思呢很洋?這個(gè)key path只是一個(gè)我們想要實(shí)現(xiàn)動(dòng)畫效果的屬性隧枫。這個(gè)是CALayer對(duì)象的一個(gè)屬性官脓,也是我們使用keyframe動(dòng)畫所真正要操縱的屬性确买。還記得為什么核心動(dòng)畫的主力是CALayer么湾趾?
JNWSpringAnimation *scale =
[JNWSpringAnimation animationWithKeyPath:@"transform.scale"];
scale.damping = 9;
scale.stiffness = 100;
scale.mass = 2;
我們也必須要JNWSpringAnimation知道要哪些屬性產(chǎn)生動(dòng)畫效果,也要知道這些屬性的開始值和終值铛楣。
JNWSpringAnimation *scale =
[JNWSpringAnimation animationWithKeyPath:@"transform.scale"];
scale.damping = 9;
scale.stiffness = 100;
scale.mass = 2;
scale.fromValue = @(1.0);
scale.toValue = @(2.0);
既然JNWSpringAnimation知道動(dòng)畫的初始值和終值以及我們想要模仿的彈簧效果簸州,現(xiàn)在我們可以將這些效果賦值給我們想要進(jìn)行動(dòng)畫的小球的層(CALayer)了岸浑。
JNWSpringAnimation *scale =
[JNWSpringAnimation animationWithKeyPath:@"transform.scale"];
scale.damping = 9;
scale.stiffness = 100;
scale.mass = 2;
scale.fromValue = @(1.0);
scale.toValue = @(2.0);
[redBall.layer addAnimation:scale forKey:scale.keyPath];
核心動(dòng)畫包含有三個(gè)layer層矢洲,每個(gè)曾都在展示屏幕內(nèi)容中發(fā)揮著至關(guān)重要的作用。
- 模態(tài)層(model layer )模態(tài)層顯示layer的所有屬性责静,即使是靜態(tài)的沒有動(dòng)畫的灾螃。例如腰鬼,我們給一個(gè)矩形設(shè)置圓角屬性靴拱,我們就是給模態(tài)層的屬性進(jìn)行設(shè)置袜炕。每當(dāng)你修改layer的一個(gè)屬性值偎窘,都會(huì)更新模態(tài)層。模態(tài)層中的屬性在動(dòng)畫過程中不會(huì)改變他托,并且能夠反映添加動(dòng)畫之前的一些狀況赏参。
- 展示層(presentation layer)這個(gè)層顯示一些正在進(jìn)行動(dòng)畫的一些屬性把篓,不應(yīng)該設(shè)置這個(gè)層中額一些屬性韧掩,相反的窖铡,你可以從當(dāng)前l(fā)ayer中讀取一些當(dāng)前動(dòng)畫中l(wèi)ayer的一些屬性。
- 渲染層(render)用來(lái)真正的渲染屏幕上的一些圖形口芍。你不需要和它進(jìn)行交互或者式知道現(xiàn)在的狀態(tài)阶界。
當(dāng)我們給一個(gè)層添加動(dòng)畫的時(shí)候聋庵,動(dòng)畫操縱的是展示層的值祭玉,而當(dāng)完成時(shí)候脱货,動(dòng)畫就會(huì)自動(dòng)從當(dāng)前層上移除而且這個(gè)層的值也會(huì)回到layer真實(shí)的靜態(tài)的值振峻。
JNWSpringAnimation *scale =
[JNWSpringAnimation animationWithKeyPath:@"transform.scale"];
scale.damping = 9;
scale.stiffness = 100;
scale.mass = 2;
scale.fromValue = @(1.0);
scale.toValue = @(2.0);
[redBall.layer addAnimation:scale forKey:scale.keyPath];
redBall.transform = CGAffineTransformMakeScale(2.0, 2.0);
通過手動(dòng)的將transform
的值改為2.0倍扣孟,layer也會(huì)保持在最終值的狀態(tài)凤价。
你也許會(huì)想拔创,當(dāng)我們用UIView動(dòng)畫的時(shí)候并沒有遇到這種問題嘛剩燥。UIView的block形式是創(chuàng)建動(dòng)畫的一種最簡(jiǎn)便的方法灭红。但是又要受限于默認(rèn)的給定的幾種動(dòng)畫形式或者是彈簧黃動(dòng)畫的版本問題比伏。如果你想全面控制你的動(dòng)畫,你就要轉(zhuǎn)用CAAnimation葛躏,而JNWSpringAnimation就是其中一個(gè)舰攒。
JNWSpringAnimation *scale =
[JNWSpringAnimation animationWithKeyPath:@"transform.scale"];
scale.damping = 13;
scale.stiffness = 540;
scale.mass = 11;
scale.fromValue = @(1.0);
scale.toValue = @(2);
[redBall.layer addAnimation:scale forKey:scale.keyPath];
redBall.transform = CGAffineTransformMakeScale(2.0, 2.0);
這個(gè)彈簧動(dòng)畫效果就會(huì)比較慢摩窃,而且震蕩幅度相對(duì)較大猾愿,
下一個(gè)例子是沒有震蕩效果蒂秘,并且會(huì)快速的降速并且慢慢的達(dá)到最終的狀態(tài)姻僧。這就是所說的過阻尼的效果。
// All the other parts of the code are the same
scale.damping = 6;
scale.stiffness = 6;
scale.mass = 1;
接下來(lái)我們看看如何實(shí)現(xiàn)彈簧效果的旋轉(zhuǎn)動(dòng)畫:
JNWSpringAnimation *scale =
[JNWSpringAnimation animationWithKeyPath:@"transform.rotation"];
scale.damping = 10;
scale.stiffness = 100;
scale.mass = 3;
scale.fromValue = @(0);
scale.toValue = @(M_PI_2);
[redBall.layer addAnimation:scale forKey:scale.keyPath];
redBall.transform = CGAffineTransformMakeRotation(M_PI_2);
因?yàn)槭莻€(gè)旋轉(zhuǎn)動(dòng)畫,所以初始值和最終值都會(huì)是通過弧度制來(lái)進(jìn)行定義的艘狭,為了方便喘蟆,我們使用CGAffineTransformMakeRotation()
函數(shù)來(lái)設(shè)置模態(tài)層的值蕴轨。
JNWSpringAnimation *scale = [JNWSpringAnimation
animationWithKeyPath:@"transform.translation.x"];
scale.damping = 7;
scale.stiffness = 7;
scale.mass = 1;
scale.fromValue = @(0);
scale.toValue = @(400);
[redBall.layer addAnimation:scale forKey:scale.keyPath];
redBall.transform = CGAffineTransformMakeTranslation(400, 0);
為了達(dá)到最終效果歧寺,我們通過CGAffineTransformMakeTranslation(400, 0)
屬性來(lái)設(shè)置transform屬性的值棘脐。
JNWSpringAnimation *scale = [JNWSpringAnimation
animationWithKeyPath:@"transform.scale"];
scale.damping = 9;
scale.stiffness = 9;
scale.mass = 1;
scale.fromValue = @(1);
scale.toValue = @(4.0);
[redBall.layer addAnimation:scale forKey:scale.keyPath];
redBall.transform = CGAffineTransformScale(redBall.transform, 4.0, 4.0);
JNWSpringAnimation *rotate = [JNWSpringAnimation
animationWithKeyPath:@"transform.rotation"];
rotate.damping = 9;
rotate.stiffness = 9;
rotate.mass = 1;
rotate.fromValue = @(0);
rotate.toValue = @(M_PI);
[redBall.layer addAnimation:rotate forKey:rotate.keyPath];
redBall.transform = CGAffineTransformRotate(redBall.transform, M_PI);
第一個(gè)動(dòng)畫是一個(gè)尺寸從1.0 ~ 4.0倍大小變化的動(dòng)畫蛀缝,第一個(gè)不同點(diǎn)是,這個(gè)動(dòng)畫結(jié)合了之前的例子的效果嗤练。
這里我們使用了CGAffineTransformScale()
而不是CGAffineTransformMakeScale()
函數(shù)煞抬,CGAffineTransformMakeScale()
,使用這個(gè)函數(shù)的原因是我們把當(dāng)前的變化效果作為第一個(gè)參數(shù)革答,一起操縱這個(gè)layer的轉(zhuǎn)變矩陣残拐。