實現(xiàn)動畫方式深度解析(九) —— Core Animation之構(gòu)建圖層層級 (六)

版本記錄

版本號 時間
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ī)則非常精確地控制圖層的大小和位置。

Constraint layout manager attributes

每個約束對象沿同一個軸封裝兩個層之間的一個幾何關(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)建此示例的子層和約束的代碼。

Example constraints based layout
// 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)容被剪切。

Clipping sublayers to the parent’s bounds

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ù)~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末苞俘,一起剝皮案震驚了整個濱河市盹沈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吃谣,老刑警劉巖乞封,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異基协,居然都是意外死亡歌亲,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門澜驮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陷揪,“玉大人,你說我怎么就攤上這事『凡” “怎么了卦绣?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長飞蚓。 經(jīng)常有香客問我滤港,道長,這世上最難降的妖魔是什么趴拧? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任溅漾,我火速辦了婚禮,結(jié)果婚禮上著榴,老公的妹妹穿的比我還像新娘添履。我一直安慰自己,他們只是感情好脑又,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布暮胧。 她就那樣靜靜地躺著,像睡著了一般问麸。 火紅的嫁衣襯著肌膚如雪往衷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天严卖,我揣著相機與錄音席舍,去河邊找鬼。 笑死妄田,一個胖子當著我的面吹牛俺亮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疟呐,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼东且!你這毒婦竟也來了启具?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤珊泳,失蹤者是張志新(化名)和其女友劉穎鲁冯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體色查,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡薯演,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了秧了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跨扮。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出衡创,到底是詐尸還是另有隱情帝嗡,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布璃氢,位于F島的核電站哟玷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏一也。R本人自食惡果不足惜巢寡,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦鹅搪、人聲如沸稚瘾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春挨稿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背京痢。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工奶甘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人祭椰。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓臭家,卻偏偏與公主長得像,于是被迫代替她去往敵國和親方淤。 傳聞我的和親對象是個殘疾皇子钉赁,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

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