個人對動畫的理解:CALayer的屬性變化了拴签,如果添加了動畫事務(wù)运挫,就會在屏幕上顯現(xiàn)了動畫,而動畫的根本原理是亲配,當(dāng)你設(shè)置了動畫的fromValue尘应,duration等數(shù)據(jù)時候,其實(shí)是設(shè)置了CALayer的相應(yīng)屬性在presentationLayer的變化數(shù)據(jù)(變化需要的時間吼虎,變化的起始點(diǎn)等)犬钢,然后每次CALayer的相應(yīng)屬性變化,都會觸發(fā)drawInContex之類的繪圖方法中用新的相應(yīng)屬性值重新繪圖思灰。說白了:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 動畫是CALayer屬性的變化數(shù)據(jù)玷犹。
所以形成動畫需要兩個要求:1.屬性有不斷變化的數(shù)據(jù);2.屬性可以在繪圖函數(shù)不斷被重新繪制洒疚。
注意:動畫跟修改CALayer內(nèi)部屬性逐漸變換是不一樣的歹颓,動畫修改的是presentationLayer的數(shù)據(jù),修改CALayer內(nèi)部屬性逐漸變換是修改modelLayer的數(shù)據(jù)油湖。presentationLayer 是CALayer眼睛看到屏幕上CALayer的位置巍扛,而實(shí)際上CALayer還在modelLayer位置上。這也就是為什么動畫結(jié)束后乏德,如果不使用下面的代碼电湘,CALayer還會回到原來位置,因?yàn)閙odelLayer的數(shù)據(jù)并沒有修改鹅经。所以使用下面代碼或者強(qiáng)制修改modelLayer的數(shù)據(jù)寂呛,CALayer就不會動畫結(jié)束后跳回去了。
animation.fillMode = kCAFillModeForward;
animation.removedOnCompletion =NO;
removedOnCompletion 表示動畫結(jié)束后是否要移除動畫瘾晃,NO表示不移除贷痪。
fillMode 表示動畫停止時,動畫展現(xiàn)在哪里蹦误,可以向前展現(xiàn)(動畫結(jié)束時)劫拢,向后展現(xiàn)(動畫開始時)肉津,或者兩者都是,或者默認(rèn)舱沧。
注意這個代碼并不是修改了modelLayer數(shù)據(jù)妹沙,它只是強(qiáng)制CALayer留在動畫最后,所以CALayer和CALayer所在的UIView在屏幕上所看到的位置并不能接收點(diǎn)擊事件熟吏。
子類CALayer自定義屬性的動畫:
1.子類CALayer的自定義屬性如果是CAShapeLayer距糖,改變CAShapeLayer進(jìn)行改變時,如縮放牵寺,旋轉(zhuǎn)等悍引,會自動動畫。CAShapeLayer是CALayer的一個子類帽氓,我們使用這個CAShapeLayer相當(dāng)于使用了CALayer趣斤,除了根圖層外,子圖層的屬性都會自動動畫黎休,這是隱式動畫浓领。
2.如果子類CALayer的自定義屬性是其他,如float(CALayer自定義屬性不能是對象势腮,否則需要下面注意的處理)等联贩,首先需要屏蔽掉float屬性的setter和getter(@dynamic),使用CALayer給float定義的setter方法(這個我們看不見)嫉鲸,然后使用+needsDisplayForKey方法撑蒜,告訴runtime這個float屬性改變時,需要重新調(diào)用CALayer的-display方法玄渗,此時修改float屬性 并不會觸發(fā)動畫(因?yàn)閒loat屬性并沒有設(shè)置動畫座菠,即變化數(shù)據(jù)),我們需要使用-(id)actionForKey:方法里面定義float的動畫(也就是上面說的float的變化數(shù)據(jù))藤树。這樣就實(shí)現(xiàn)了對一個子類CALayer自定義屬性的動畫浴滴,由此可以推測CALayer的屬性變化產(chǎn)生的動畫都是由-(id)actionForKey:來注冊,使用+needsDisplayForKey觸發(fā)display來更新幀岁钓。
注意:
在drawInContex之類的繪圖方法中升略,盡量避免CGContextDrawImageInRect之類的元繪圖調(diào)用,因?yàn)檫@些元繪圖操作非常耗時屡限,也是硬件加速幫不上忙的地方品嚣,盡量通過將CGImageRef傳給CALayer.contents屬性的方法把內(nèi)容事先做好傳給CALayer,然后通過仿射或者3D transform的方法來進(jìn)行動畫變換钧大,? 因?yàn)榉律浠蛘?D transform是完全硬件加速的翰撑,它比自己書寫繪圖代碼要快的多的多? 。
layer方法響應(yīng)鏈有三種:
1. [layer setNeedDisplay] -> [layer displayIfNeed] -> [layer display] -> [layerDelegate displayLayer:]
2. [layer setNeedDisplay] -> [layer displayIfNeed] -> [layer display] -> [layer drawInContext:] -> [layerDelegate drawLayer: inContext:]?
3.[layer setNeedDisplay] -> [layer displayIfNeed] -> [layer display] -> [layer drawInContext:] -> [layerDelegate drawRect:] (這個只有圖層樹的根圖層才有)
子類化CALayer時啊央,有個地方要注意眶诈,因?yàn)镃oreAnimation在生成中間幀的方式涨醋,是通過Copy操作生成了一大堆中間幀用的CALayer,它在復(fù)制CALayer的數(shù)據(jù)時逝撬,只能對CALayer原有的屬性成員進(jìn)行copy浴骂,不會copy后添加的諸如對象引用一類的東西,這就需要程序員重載(這也就是Layer 中自定義屬性的動畫這篇博文中宪潮,第二個例子不用NSDate的原因)
-?(id)initWithLayer:(id)layer
{
? ? ? ?self=?[super?initWithLayer:layer];
? ? ? ?if(self?!=?nil)?{
? ? ? ? ?MyLayer?*myLayer=?(MyLayer*)layer;
? ? ? ? self.aUIImage=cl.aUIImage;
? ? ? }
? ?return?(self);
}