版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.09.23 |
前言
app中好的炫的動畫可以讓用戶耳目一新匿情,為產(chǎn)品增色不少,關(guān)于動畫的實現(xiàn)我們可以用基本動畫、關(guān)鍵幀動畫渔呵、序列幀動畫以及基于CoreGraphic的動畫等等,接下來這幾篇我就介紹下我可以想到的幾種動畫繪制方法砍鸠。具體Demo示例已開源到Github —— 刀客傳奇扩氢,感興趣的可以看我寫的另外幾篇。
1. 實現(xiàn)動畫方式深度解析(一) —— 播放GIF動畫(一)
2. 實現(xiàn)動畫方式深度解析(二) —— 播放GIF動畫之框架FLAnimatedImage的使用(二)
3. 實現(xiàn)動畫方式深度解析(三) —— 播放序列幀動畫(一)
4. 實現(xiàn)動畫方式深度解析(四) —— QuartzCore框架(一)
5. 實現(xiàn)動畫方式深度解析(五) —— QuartzCore框架之CoreAnimation(二)
6. 實現(xiàn)動畫方式深度解析(六) —— Core Animation Basics(三)
7. 實現(xiàn)動畫方式深度解析(七) —— Core Animation之Setting Up Layer Objects(四)
8. 實現(xiàn)動畫方式深度解析(八) —— Core Animation之動畫層內(nèi)容 (五)
Building a Layer Hierarchy - 構(gòu)建圖層層次結(jié)構(gòu)
大多數(shù)情況下爷辱,在應(yīng)用程序中使用圖層的最佳方法是將它們與視圖對象結(jié)合使用录豺。 但是朦肘,有時您可能需要通過向其添加其他圖層對象來增強視圖層次結(jié)構(gòu)。 在這樣做時双饥,您可以使用使用層提供更好的性能媒抠,或者讓您實現(xiàn)一個單獨使用視圖很難處理的功能。 在這種情況下咏花,您需要知道如何管理您創(chuàng)建的層次結(jié)構(gòu)趴生。
重要提示:在OS X v10.8及更高版本中,建議您最小化對層次結(jié)構(gòu)的使用昏翰,并僅使用層支持的視圖苍匆。 在該版本的OS X中引入的層重繪策略允許您自定義層次支持的視圖的行為,并且仍然可以獲得之前使用獨立圖層獲得的那種性能棚菊。
Arranging Layers into a Layer Hierarchy - 將層布置到層次結(jié)構(gòu)中
層次layer結(jié)構(gòu)在很多方面都是和視圖view結(jié)構(gòu)類似的浸踩。 您將一層嵌入另一層以在嵌入層(稱為子層)與父層(稱為超層)之間創(chuàng)建親子關(guān)系。 這個親子關(guān)系影響子層的各個方面统求。 例如检碗,其內(nèi)容位于其父級的內(nèi)容之上,其位置相對于其父級的坐標系來指定码邻,并且受到應(yīng)用于父級的任何轉(zhuǎn)換的影響折剃。
1. Adding, Inserting, and Removing Sublayers - 增加、插入和刪除子層
每個層對象都有添加冒滩,插入和刪除子層的方法微驶。 下表總結(jié)了這些方法及其行為。
行為 | 方法 | 描述 |
---|---|---|
增加layer | addSublayer: | 向當前圖層添加一個新的子圖層對象开睡。 子層被添加到層的子層列表的末尾因苹。 這會導(dǎo)致子層在其zPosition屬性中以相同的值出現(xiàn)在任何兄弟圖層之上 |
插入layer | insertSublayer:above: insertSublayer:atIndex: insertSublayer:below: | 在指定的索引或相對于另一個子層的位置插入子層到子層層次結(jié)構(gòu)中。 當插入另一個子層的上方或下方時篇恒,您只在子層數(shù)組中指定子層的位置扶檐。 層的實際可見性主要由其zPosition屬性中的值確定,其次由它們在子層數(shù)組中的位置確定胁艰。 |
移除layer | removeFromSuperlayer | 從父層中移除子層 |
交換layer | replaceSublayer:with: | 交換一個子層與另一個子層款筑。 如果要插入的子層已經(jīng)在另一個層次結(jié)構(gòu)中,則會從該層次結(jié)構(gòu)中先刪除它腾么。 |
使用您自己創(chuàng)建的圖層對象時奈梳,可以使用上述方法。 您不會使用這些方法來排列屬于圖層支持視圖的圖層解虱。 但是攘须,層次支持的視圖可以作為您自己創(chuàng)建的獨立圖層的父級。
2. Positioning and Sizing Sublayers - 定位和調(diào)整子層
添加和插入子層時殴泰,您必須在子屏幕出現(xiàn)之前設(shè)置子層的大小和位置于宙。 在添加到層次結(jié)構(gòu)中之后浮驳,您可以修改子層的大小和位置,但是在創(chuàng)建層時應(yīng)該習(xí)慣設(shè)置這些值捞魁。
您使用bounds屬性設(shè)置子層的大小至会,并使用position屬性將其位置設(shè)置在其超層內(nèi)。 邊界矩形的起點幾乎總是(0谱俭,0)奉件,而大小是您為點指定的層所需的任何大小。 位置屬性中的值相對于默認情況下位于圖層中心的圖層的錨點進行解釋旺上。 如果不為這些屬性分配值瓶蚂,Core Animation將圖層的初始寬度和高度設(shè)置為0糖埋,并將位置設(shè)置為(0,0)宣吱。
myLayer.bounds = CGRectMake(0, 0, 100, 100);
myLayer.position = CGPointMake(200, 200);
重要提示:始終對圖層的寬度和高度使用整數(shù)。
3. How Layer Hierarchies Affect Animations - 圖層層級是如何影響到動畫的
某些超層的屬性可能會影響應(yīng)用于其子層的任何動畫的行為瞳别。 一個這樣的屬性是速度屬性征候,它是動畫速度的乘數(shù)。 此屬性的值默認設(shè)置為1.0祟敛,但將其更改為2.0會導(dǎo)致動畫以原始速度的兩倍運行疤坝,從而在一半時間內(nèi)完成。 此屬性不僅影響其設(shè)置的圖層馆铁,還會影響該圖層的子圖層跑揉。 這種變化也是乘法的。 如果子層及其超層速度為2.0埠巨,則子層上的動畫以其原始速度的四倍運行历谍。
大多數(shù)其他層次更改可以以可預(yù)測的方式影響任何包含的子層。 例如辣垒,將旋轉(zhuǎn)變換應(yīng)用于層將旋轉(zhuǎn)該層及其所有子層望侈。 類似地,更改圖層的不透明度會改變其子圖層的不透明度勋桶。 對圖層大小的更改遵循Adjusting the Layout of Your Layer Hierarchies中描述的布局規(guī)則脱衙。
Adjusting the Layout of Your Layer Hierarchies - 調(diào)整層次結(jié)構(gòu)的布局
核心動畫支持幾個選項來調(diào)整子層的大小和位置以響應(yīng)其超級層的更改。 在iOS中例驹,普遍使用層次支持的視圖使得創(chuàng)建層次結(jié)構(gòu)不太重要; 僅支持手動布局更新捐韩。 對于OS X,還有其他幾個選項可以幫助您更輕松地管理層次結(jié)構(gòu)鹃锈。
如果您使用創(chuàng)建的獨立圖層對象構(gòu)建圖層層次結(jié)構(gòu)荤胁,則層級布局才是相關(guān)的。 如果您的應(yīng)用程序的圖層與視圖相關(guān)聯(lián)仪召,請使用基于視圖的布局支持來更新視圖的大小和位置以響應(yīng)更改寨蹋。
1. Using Constraints to Manage Your Layer Hierarchies in OS X - 在OS X中使用約束管理您的圖層層級
約束允許您使用層與其上層或同層之間的一組詳細關(guān)系來指定層的位置和大小松蒜。 定義約束需要以下步驟:
- 創(chuàng)建一個或多個CAConstraint對象。 使用這些對象來定義約束參數(shù)已旧。
- 將約束對象添加到其修改屬性的圖層上秸苗。
- 檢索共享的CAConstraintLayoutManager對象并分配給直接的上層。
下圖顯示了可用于定義約束的屬性以及它們影響的圖層的方面运褪。 您可以使用約束來根據(jù)相對于另一個圖層的中點邊緣的位置來更改圖層的位置惊楼。 您也可以使用它們來更改圖層的大小。 您所做的更改可能與父層成正比或與另一層相關(guān)秸讹。 您甚至可以為結(jié)果更改添加縮放因子或常數(shù)檀咙。 這種額外的靈活性使得可以使用一組簡單的規(guī)則非常精確地控制圖層的大小和位置。
每個約束對象沿同一個軸封裝兩個層之間的一個幾何關(guān)系璃诀。 可以將最多兩個約束對象分配給每個軸弧可,并且它們是確定哪個屬性是可更改的那些約束。 例如劣欢,如果為圖層的左右邊緣指定約束棕诵,則圖層的大小將更改。 如果您為圖層的左邊緣和寬度指定約束凿将,則圖層右邊緣的位置將更改校套。 如果為其中一個邊緣指定單個約束,則Core Animation將創(chuàng)建一個隱含的約束牧抵,該約束可將圖層的大小固定在給定維中笛匙。
創(chuàng)建約束時,必須始終指定三條信息:
- 要限制的層的方面
- 該層用作參考
- 參考層的方面用于比較
下面代碼顯示了一個簡單的約束犀变,將一個圖層的垂直中點定位到其上層的垂直中點妹孙。 當引用超級層時,使用字符串超層弛作。 這個字符串是一個專用名稱涕蜂,用于引用超級層。 使用它不需要有指向圖層的指針或知道圖層的名稱映琳。 它還允許您更改超級層机隙,并將約束自動應(yīng)用于新的父級。 (當創(chuàng)建相對于兄弟層的約束時萨西,您必須使用其name屬性來標識兄弟層有鹿。
//Defining a simple constraint
[myLayer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY
relativeTo:@"superlayer"
attribute:kCAConstraintMidY]];
要在運行時應(yīng)用約束,必須將共享的CAConstraintLayoutManager
對象附加到直接的上層谎脯。 每層負責(zé)管理子層的布局葱跋。 將布局管理器分配給父級會告訴Core Animation
應(yīng)用其子節(jié)點定義的約束。 布局管理器對象自動應(yīng)用約束。 在將其分配給父層之后娱俺,您不需要告訴它來更新布局稍味。
要了解限制在更具體的情況下如何工作,請參見下圖荠卷。 在該示例中模庐,設(shè)計要求層A的寬度和高度保持不變,并且層A在其超層內(nèi)保持居中油宜。 另外掂碱,層B的寬度必須與層A的寬度一致,層B的頂邊必須保持在層A的底邊下方10點慎冤,層B的底邊必須重新指向超層底部邊緣下10點疼燥。 下面代碼顯示了您將用于創(chuàng)建此示例的子層和約束的代碼。
// Setting up constraints for your layers
// Create and set a constraint layout manager for the parent layer.
theLayer.layoutManager=[CAConstraintLayoutManager layoutManager];
// Create the first sublayer.
CALayer *layerA = [CALayer layer];
layerA.name = @"layerA";
layerA.bounds = CGRectMake(0.0,0.0,100.0,25.0);
layerA.borderWidth = 2.0;
// Keep layerA centered by pinning its midpoint to its parent's midpoint.
[layerA addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY
relativeTo:@"superlayer"
attribute:kCAConstraintMidY]];
[layerA addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX
relativeTo:@"superlayer"
attribute:kCAConstraintMidX]];
[theLayer addSublayer:layerA];
// Create the second sublayer
CALayer *layerB = [CALayer layer];
layerB.name = @"layerB";
layerB.borderWidth = 2.0;
// Make the width of layerB match the width of layerA.
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth
relativeTo:@"layerA"
attribute:kCAConstraintWidth]];
// Make the horizontal midpoint of layerB match that of layerA
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX
relativeTo:@"layerA"
attribute:kCAConstraintMidX]];
// Position the top edge of layerB 10 points from the bottom edge of layerA.
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMaxY
relativeTo:@"layerA"
attribute:kCAConstraintMinY
offset:-10.0]];
// Position the bottom edge of layerB 10 points
// from the bottom edge of the parent layer.
[layerB addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMinY
relativeTo:@"superlayer"
attribute:kCAConstraintMinY
offset:+10.0]];
[theLayer addSublayer:layerB];
關(guān)于上面代碼的一個有趣的事情是代碼不會明確地設(shè)置layerB的大小蚁堤。 由于定義的約束醉者,每次布局更新時都會自動設(shè)置layerB的寬度和高度。 因此违寿,使用邊界矩形設(shè)置大小是不必要的湃交。
警告:創(chuàng)建約束時熟空,不要在約束之間創(chuàng)建循環(huán)引用藤巢。 循環(huán)約束使得無法計算所需的布局信息。 遇到這樣的循環(huán)引用時息罗,布局行為是未定義的掂咒。
2. Setting Up Autoresizing Rules for Your OS X Layer Hierarchies - 為您的OS X層次結(jié)構(gòu)設(shè)置自動調(diào)整規(guī)則
自動調(diào)整規(guī)則是在OS X中調(diào)整圖層大小和位置的另一種方法。通過自動調(diào)整規(guī)則迈喉,您可以指定圖層的邊緣是否應(yīng)保持與超層相應(yīng)邊緣固定或可變距離绍刮。 您可以類似地指定圖層的寬度或高度是固定的還是可變的。 關(guān)系總是在層和它的超層之間挨摸。 您不能使用自動調(diào)整規(guī)則來指定兄弟層之間的關(guān)系孩革。
3. Manually Laying Out Your Layer Hierarchies - 手動布局層次結(jié)構(gòu)
在iOS和OS X上,您可以通過在超級層的委托對象上實現(xiàn)layoutSublayersOfLayer:
方法來手動處理布局得运。 您可以使用該方法來調(diào)整當前嵌入在圖層中的任何子圖層的大小和位置膝蜈。 當進行手動布局更新時,由您執(zhí)行必要的計算來定位每個子層熔掺。
如果要實現(xiàn)自定義層子類饱搏,則您的子類可以覆蓋layoutSublayers
方法,并使用該方法(而不是委托)來處理任何布局任務(wù)置逻。 在您需要完全控制自定義圖層類中子圖層的位置的情況下推沸,才應(yīng)該覆蓋此方法。 替換默認實現(xiàn)會阻止Core Animation在OS X上應(yīng)用約束或自動調(diào)整規(guī)則。
Sublayers and Clipping - 子圖層和裁剪
與視圖不同鬓催,超層不會自動剪貼位于其邊界矩形之外的子圖層的內(nèi)容肺素。 相反,默認情況下宇驾,超級層允許其子層完全顯示压怠。 但是,您可以通過將圖層的masksToBounds
屬性設(shè)置為YES來重新啟用裁剪飞苇。
層的剪裁蒙版的形狀包括層的角半徑菌瘫,如果指定了它的角半徑。 下圖顯示了一個層布卡,它演示了maskToBounds
屬性如何影響具有圓角的圖層雨让。 當屬性設(shè)置為NO時,子圖層將全部顯示忿等,即使它們超出了其父層的邊界栖忠。 將屬性更改為YES會導(dǎo)致其內(nèi)容被剪切。
Converting Coordinate Values Between Layers - 層之間轉(zhuǎn)換坐標值
偶爾贸街,您可能需要將一層中的坐標值轉(zhuǎn)換為不同圖層中相同屏幕位置的坐標值庵寞。 CALayer類提供了一組可用于此目的的簡單轉(zhuǎn)換程序:
除了轉(zhuǎn)換點和矩形值之外,還可以使用convertTime:fromLayer:和convertTime:toLayer:方法來轉(zhuǎn)換圖層之間的時間值薛匪。 每個層定義自己的本地時間空間捐川,并使用該時間空間將動畫的開始和結(jié)束與系統(tǒng)的其余部分同步。 這些時間空間默認同步; 但是逸尖,如果更改一組圖層的動畫速度古沥,那么這些圖層的時間空間將相應(yīng)更改。 您可以使用時間轉(zhuǎn)換方法來解決任何這些因素娇跟,并確保兩個層的時間同步岩齿。
后記
未完,待續(xù)~~