Objective-C的CALayer學(xué)習(xí)筆記

CALayer簡(jiǎn)介

CALayer(圖層)通常用于存儲(chǔ)和管理UIView(視圖)的視覺內(nèi)容(比如背景顏色、邊框和陰影)囚玫,創(chuàng)建的UIView會(huì)持有一個(gè)從不為nil的layer屬性,可以用來訪問UIView的CALayer事镣,也就是UIView顯示的視覺內(nèi)容實(shí)際上是有CALayer來呈現(xiàn)的诲锹。但由于CALayer不能與用戶進(jìn)行交互状囱,但是UIView可以,所以這兩個(gè)對(duì)象更像明確的劃分了功能旭蠕,CALayer呈現(xiàn)視覺內(nèi)容停团,UIView響應(yīng)事件旷坦。

CALayer除了管理呈現(xiàn)的視覺內(nèi)容之外,還維護(hù)用于在屏幕上顯示的視覺內(nèi)容的相關(guān)的幾何形狀信息(如position(位置)佑稠、大小(size)和轉(zhuǎn)換(transform))秒梅。可以使用修改CALayer的視覺內(nèi)容相關(guān)屬性或幾何形狀信息相關(guān)屬性來啟動(dòng)動(dòng)畫舌胶,CALayer對(duì)象通過定義CALayer計(jì)時(shí)信息的CAMediaTiming協(xié)議封裝CALayer及其動(dòng)畫的持續(xù)時(shí)間和速度捆蜀。

如果CALayer對(duì)象是由UIView創(chuàng)建的,則UIView通常會(huì)自動(dòng)將自身指定為CALayer的代理幔嫂,并且不應(yīng)更改該關(guān)系辆它。對(duì)于自己創(chuàng)建的在沒有視圖的情況下用于顯示內(nèi)容CALayer對(duì)象,可以為其指定代理對(duì)象婉烟。

CALayer的常用屬性
@property CGRect bounds;

屬性描述CALayer對(duì)象的邊界娩井,默認(rèn)為CGRectZero,可設(shè)置動(dòng)畫似袁。

@property CGPoint position;

屬性描述CALayer對(duì)象邊界矩形相對(duì)其父級(jí)層(superlayer)的定位點(diǎn)位置洞辣。默認(rèn)為CGPointZero£夹疲可設(shè)置動(dòng)畫扬霜。

@property CGPoint anchorPoint;

屬性描述定位CALayer對(duì)象邊界矩形的錨點(diǎn),可以做成動(dòng)畫而涉。使用單位坐標(biāo)空間指定此屬性的值著瓶。此屬性的默認(rèn)值為(0.5,0.5),它表示CALayer(圖層)對(duì)象邊界矩形的中心啼县。視圖的所有幾何操作都發(fā)生在指定的點(diǎn)上材原,例如對(duì)具有默認(rèn)錨點(diǎn)的圖層應(yīng)用旋轉(zhuǎn)變換會(huì)導(dǎo)致該圖層繞其中心旋轉(zhuǎn),將錨點(diǎn)更改為一個(gè)不同的位置將導(dǎo)致圖層圍繞新點(diǎn)旋轉(zhuǎn)季眷。

@property CGFloat zPosition;

屬性描述CALayer對(duì)象在Z軸上的位置余蟹,可設(shè)置動(dòng)畫,此屬性的默認(rèn)值為0子刮。更改此屬性的值將更改屏幕上各CALayer(圖層)對(duì)象的前到后順序威酒。與值較低的層相比,值較高的層在視覺上更靠近查看器挺峡。這會(huì)影響框架矩形重疊的CALayer(圖層)對(duì)象的可見性葵孤。

\color{red}{zPosition使用示例,例如:要讓表視圖的某一cell這樣顯示:}

cell = [tableView dequeueReusableCellWithIdentifier:YSCUserCenterTitleCellReuseIdentifier];
cell.layer.zPosition = 10;
Jietu20191127-212056@2x.gif

可以讓上部的cell中設(shè)置背景的視圖底部約束超出cell橱赠,但在沒有設(shè)置zPosition屬性時(shí)尤仍,可能是這樣的:

Jietu20191127-212804@2x.gif
@property(getter=isHidden) BOOL hidden;

屬性描述隱藏CALayer對(duì)象及其子層(sublayer),如果為true狭姨,則不顯示CALayer對(duì)象及其子層(sublayer)宰啦。默認(rèn)為“ NO”鲤嫡,可設(shè)置動(dòng)畫。

@property(nullable, readonly) CALayer *superlayer;

屬性描述調(diào)用方的superlayer(父級(jí)層)對(duì)象绑莺。隱式更改以匹配“sublayers”屬性描述的層次結(jié)構(gòu)暖眼。

@property BOOL masksToBounds;

屬性描述 : 一個(gè)布爾值,指示CALayer對(duì)象的子層(sublayers)超出邊界的部分是否將剪裁纺裁,可設(shè)置動(dòng)畫诫肠。

@property(nullable, strong) id contents;

屬性描述提供圖層內(nèi)容的對(duì)象,可設(shè)置動(dòng)畫欺缘,此屬性的默認(rèn)值為nil栋豫。如果使用CALayer對(duì)象來顯示靜態(tài)圖像,可以將此屬性設(shè)置為包含想要顯示的圖像的CGImageRef對(duì)象谚殊。如果CALayer對(duì)象綁定到一個(gè)視圖對(duì)象丧鸯,則應(yīng)該避免直接設(shè)置這個(gè)屬性的內(nèi)容,因?yàn)橐晥D和圖層之間的相互作用通常會(huì)導(dǎo)致視圖在隨后的更新中替換該屬性的內(nèi)容嫩絮。

@property(copy) CALayerContentsGravity contentsGravity;

屬性描述 :一個(gè)常量丛肢,指定CALayer(圖層)對(duì)象的內(nèi)容在其邊界內(nèi)的定位或縮放方式,此屬性的默認(rèn)值為kCAGravityResize剿干。

\color{red}{例如 :給圖層設(shè)置一張靜態(tài)圖片:}

CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(100, 150, 200, 200);
layer.contents = (id)[UIImage imageNamed:@"PokemonV"].CGImage;
layer.contentsGravity = kCAGravityResize;
[self.view.layer addSublayer:layer];
截屏2022-07-06 13.39.00.png
@property CGRect contentsRect;

屬性描述 :定義了將要繪制到圖層中的contents屬性的子矩形蜂怎,默認(rèn)為單位矩形(0.0, 0.0, 1.0, 1.0),可以動(dòng)畫置尔。如果請(qǐng)求單元矩形外的像素杠步,則contents圖像的邊緣像素將向外擴(kuò)展。如果提供了一個(gè)空矩形榜轿,則結(jié)果是未定義的幽歼。

例如 : layer.contentsRect = CGRectMake(0.0, 0.0, 0.5, 0.5)時(shí):

截屏2022-07-06 13.41.18.png

layer.contentsRect = CGRectMake(0.0, 0.0, 1.5, 1.5)時(shí):

截屏2022-07-06 13.42.15.png
@property CGFloat cornerRadius;

屬性描述繪制CALayer對(duì)象背景圓角時(shí)使用的半徑,可設(shè)置動(dòng)畫谬盐。將半徑設(shè)置為大于0.0的值會(huì)導(dǎo)致圖層開始在其背景上繪制圓角甸私,默認(rèn)情況下,角半徑不應(yīng)用于層的contents屬性中的圖像设褐,它只適用于圖層的背景顏色和邊框颠蕴,但是如果將masksToBounds屬性設(shè)置為YES泣刹,會(huì)導(dǎo)致contents屬性中的圖像剪切到圓角助析。

@property CGFloat borderWidth;

屬性描述CALayer對(duì)象邊框的寬,可以做成動(dòng)畫椅您。當(dāng)該值大于0.0時(shí)外冀,根據(jù)此屬性中指定的值在調(diào)用方邊界插入屬性中指定的值來繪制邊框,使用當(dāng)前的borderColor值設(shè)置顏色掀泳,并最終在調(diào)用方的內(nèi)容和子層之上合成雪隧,并包括cornerRadius特性的影響西轩。此屬性的默認(rèn)值為0.0。

@property(nullable) CGColorRef borderColor;

屬性描述CALayer對(duì)象邊框的顏色脑沿,可以做成動(dòng)畫藕畔,此屬性的默認(rèn)值是不透明的黑色犁罩。

@property float shadowOpacity;

屬性描述CALayer對(duì)象陰影的不透明度坚踩,可以做成動(dòng)畫,此屬性中的值必須在0.0(透明)到1.0(不透明)的范圍內(nèi)澎埠,這個(gè)屬性的默認(rèn)值是0.0措近。

@property(nullable) CGColorRef shadowColor;

屬性描述CALayer對(duì)象陰影的顏色溶弟,可以做成動(dòng)畫,此屬性的默認(rèn)值是不透明的黑色瞭郑。

@property CGSize shadowOffset;

屬性描述CALayer對(duì)象陰影陰影的偏移(以點(diǎn)為單位)辜御,這個(gè)屬性的默認(rèn)值是(0.0,-3.0)屈张,寬度為負(fù)時(shí)陰影左移擒权,寬度為正時(shí)陰影右移,高度為負(fù)時(shí)陰影上移阁谆,高度為正時(shí)陰影下移菜拓,可以做成動(dòng)畫。

@property CGFloat shadowRadius;

屬性描述用于渲染CALayer對(duì)象陰影的模糊半徑(以點(diǎn)為單位)笛厦,這個(gè)屬性的默認(rèn)值是3.0纳鼎,可以做成動(dòng)畫。

@property(nullable) CGPathRef shadowPath;

屬性描述CALayer(圖層)對(duì)象陰影的形狀裳凸,該屬性的默認(rèn)值為nil贱鄙,這將導(dǎo)致該CALayer(圖層)對(duì)象使用標(biāo)準(zhǔn)的陰影形狀。如果為這個(gè)屬性指定了一個(gè)值姨谷,圖層會(huì)使用指定的路徑來創(chuàng)建它的陰影輪廓逗宁,并使用非零纏繞規(guī)則(圖形學(xué)中判斷一個(gè)點(diǎn)是否在自相交的多邊形內(nèi)部或外部的規(guī)則)結(jié)合當(dāng)前陰影顏色、不透明度和模糊半徑填充創(chuàng)建的陰影形狀梦湘。與大多數(shù)可動(dòng)畫屬性不同瞎颗,這個(gè)屬性(與所有CGPathRef可動(dòng)畫屬性一樣)不支持隱式動(dòng)畫,但是路徑對(duì)象可以使用CAPropertyAnimation的任何具體子類進(jìn)行動(dòng)畫捌议。

\color{red}{例如 :添加圓形的陰影:}

CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(100, 150, 200, 200);
layer.contents = (id)[UIImage imageNamed:@"PokemonV"].CGImage;
layer.contentsGravity = kCAGravityResize;
layer.cornerRadius = 10.0;
layer.shadowOpacity = 0.5f;
layer.shadowOffset = CGSizeMake(-50, -50);
layer.shadowColor = [UIColor redColor].CGColor;
layer.shadowRadius = 10.0f;
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 300, 300)];
layer.shadowPath = path.CGPath;
[self.view.layer addSublayer:layer];
截屏2022-07-08 09.14.07.png
@property(nullable) CGColorRef backgroundColor;

屬性描述CALayer對(duì)象的背景顏色哼拔,此屬性的默認(rèn)值為nil,可以做成動(dòng)畫瓣颅。

@property CGFloat rasterizationScale;

屬性描述相對(duì)于圖層的坐標(biāo)空間倦逐,光柵化內(nèi)容的比例」梗可設(shè)置動(dòng)畫

@property BOOL shouldRasterize;

屬性描述光柵化檬姥,指示layer在合成之前是否被渲染為位圖的布爾值曾我,可動(dòng)畫。啟用shouldRasterize屬性會(huì)將圖層繪制到一個(gè)屏幕之外的圖像健民,然后這個(gè)圖像將會(huì)被緩存起來抒巢。

如果有很多的子圖層或者有復(fù)雜的效果應(yīng)用,開啟shouldRasterize就會(huì)比重繪所有事務(wù)的所有幀劃得來得多秉犹。但是光柵化原始圖像需要時(shí)間虐秦,而且還會(huì)消耗額外的內(nèi)存。所以需要根據(jù)實(shí)際情況取舍凤优。單次使用或者視圖有變動(dòng)悦陋,shouldRasterize不會(huì)有任何用途,反而會(huì)犧牲內(nèi)存筑辨。對(duì)一個(gè)層級(jí)復(fù)雜的視圖做動(dòng)畫時(shí)俺驶,可以啟用shouldRasterize避免GPU每幀都重新合成。

調(diào)試方法:

xcode開發(fā)工具提供的常用的測(cè)量方式:

Xcode->Debug->View Debuging->Rendering->Color Offscrenn-rended Yellow可以為觸發(fā)了離屏渲染的layer著黃色棍辕。

Xcode->Debug->View Debuging->Rendering->Hits Green and Misses Red
這個(gè)指標(biāo)可以反映我們通過嘗試開啟shouldRasterize提升性能的時(shí)候是不是達(dá)到了預(yù)期效果暮现。

當(dāng)使用shouldRasterize屬性的時(shí)候,耗時(shí)的圖層繪制會(huì)被緩存楚昭,然后當(dāng)做一個(gè)簡(jiǎn)單的扁平圖片呈現(xiàn)栖袋。當(dāng)緩存再生的時(shí)候這個(gè)選項(xiàng)就用紅色對(duì)柵格化圖層進(jìn)行了高亮,緩存被重復(fù)使用的話就會(huì)以綠色進(jìn)行高亮抚太。如果緩存頻繁再生的話(紅色太多)塘幅,就意味著柵格化可能會(huì)有負(fù)面的性能影響了。

CALayer的常用函數(shù)
- (void)addSublayer:(CALayer *)layer;

函數(shù)描述將參數(shù)給定的CALayer對(duì)象添加到調(diào)用方的子層(sublayers)列表中尿贫。如果sublayers屬性中的數(shù)組為nil电媳,調(diào)用此方法將為sublayers屬性創(chuàng)建一個(gè)數(shù)組,并將指定的圖層添加到該屬性中庆亡。

參數(shù) :

layer : 要添加的CALayer對(duì)象匾乓。

- (void)insertSublayer:(CALayer *)layer atIndex:(unsigned)idx;

函數(shù)描述 :將參數(shù)給定的CALayer對(duì)象插入到調(diào)用方的子層列表中指定索引處的位置

參數(shù) :

layer : 要插入到當(dāng)前調(diào)用方圖層層次結(jié)構(gòu)中的子圖層對(duì)象又谋。

idx : 插入圖層的索引拼缝,該值必須是子層數(shù)組中有效的索引。

- (void)insertSublayer:(CALayer *)layer below:(nullable CALayer *)sibling;

函數(shù)描述 :將參數(shù)給定的CALayer對(duì)象插入到調(diào)用方子層列表中指定的圖層之下彰亥。

參數(shù) :

layer :要插入到當(dāng)前調(diào)用方圖層層次結(jié)構(gòu)中的子圖層對(duì)象咧七。

sibling : 調(diào)用方指定的圖層。如果指定的圖層不在調(diào)用方的子層數(shù)組中剩愧,此方法將引發(fā)異常猪叙。

- (void)insertSublayer:(CALayer *)layer above:(nullable CALayer *)sibling;

函數(shù)描述 :將參數(shù)給定的CALayer對(duì)象插入到調(diào)用方子層列表中指定的圖層之上娇斩。

參數(shù) :

layer :要插入到當(dāng)前調(diào)用方圖層層次結(jié)構(gòu)中的子圖層對(duì)象仁卷。

sibling : 調(diào)用方指定的圖層穴翩。如果指定的圖層不在調(diào)用方的子層數(shù)組中,此方法將引發(fā)異常锦积。

- (void)replaceSublayer:(CALayer *)oldLayer with:(CALayer *)newLayer;

函數(shù)描述 :使用新的CALayer對(duì)象替換調(diào)用方指定的子圖層芒帕。

參數(shù) :

oldLayer : 調(diào)用方要被替換的子圖層。

newLayer : 用來替換oldLayer的圖層對(duì)象丰介。

- (void)removeFromSuperlayer;

函數(shù)描述將CALayer對(duì)象在其父級(jí)層(superlayer)移除背蟆。可以使用此方法從圖層的層次結(jié)構(gòu)中刪除一個(gè)層(及其所有子層)哮幢。此方法更新父級(jí)層(superlayer)的子層列表(sublayers)带膀,并將該CALayer對(duì)象的父級(jí)層(superlayer)屬性設(shè)置為nil。

CALayer關(guān)于動(dòng)畫的常用函數(shù)
- (void)addAnimation:(CAAnimation *)anim forKey:(nullable NSString *)key;

函數(shù)描述在調(diào)用函數(shù)的CALayer對(duì)象上附加一個(gè)動(dòng)畫對(duì)象橙垢。通常這是通過CAAnimation對(duì)象的操作隱式調(diào)用的垛叨。

“key”可以是任何字符串,這樣每個(gè)唯一的key在每個(gè)CALayer對(duì)象上只添加一個(gè)動(dòng)畫柜某。特殊的key值“transition”是自動(dòng)用于過渡動(dòng)畫嗽元,并且nil指針也是一個(gè)有效的鍵。

如果動(dòng)畫的“duration”屬性為0或負(fù)值喂击,則會(huì)給它默認(rèn)的持續(xù)時(shí)間剂癌,否則為“animationDuration”事務(wù)屬性的值或0.25秒。

動(dòng)畫在被添加到圖層之前會(huì)被復(fù)制翰绊,所以任何對(duì)“anim”的后續(xù)修改都不會(huì)有影響佩谷,除非它被添加到另一個(gè)圖層。

參數(shù) :

anim : 要添加到渲染樹的動(dòng)畫监嗜。此對(duì)象由渲染樹復(fù)制琳要,而不是引用。因此秤茅,對(duì)對(duì)象的后續(xù)修改不會(huì)傳播到渲染樹中稚补。

key : 標(biāo)識(shí)動(dòng)畫的字符串,每一個(gè)唯一的key只有一個(gè)動(dòng)畫被添加到調(diào)用該函數(shù)的圖層框喳。特殊的key值“kCATransition”自動(dòng)用于過渡動(dòng)畫课幕,也可以為該參數(shù)指定nil。

- (void)removeAllAnimations;

函數(shù)描述 :調(diào)用該函數(shù)的CALayer對(duì)象上所附加的全部動(dòng)畫都將被刪除五垮。

- (void)removeAnimationForKey:(NSString *)key;

函數(shù)描述 : 在調(diào)用該函數(shù)的CALayer對(duì)象上移除使用指定的key標(biāo)識(shí)的動(dòng)畫對(duì)象乍惊。

參數(shù) :

key : 要移除的動(dòng)畫的標(biāo)識(shí)符。

CAGradientLayer - 顏色漸變層

CAGradientLayer繼承CALayer放仗,是可以在其背景色上繪制顏色漸變的圖層润绎,默認(rèn)情況下顏色均勻地分布在整個(gè)圖層中,但可以通過選擇指定的漸變位置來控制顏色的位置。

CAGradientLayer常用屬性
@property CGPoint startPoint;

函數(shù)描述在圖層的坐標(biāo)空間中繪制漸變時(shí)的起點(diǎn)莉撇,可設(shè)置動(dòng)畫呢蛤。起點(diǎn)對(duì)應(yīng)于梯度的第一個(gè)停止點(diǎn),該點(diǎn)在單位坐標(biāo)空間中定義棍郎,然后在繪制時(shí)映射到層的邊界矩形其障。默認(rèn)值為(0.5,0.0)。

@property CGPoint endPoint;

函數(shù)描述在圖層的坐標(biāo)空間中繪制漸變時(shí)的終點(diǎn)涂佃,可設(shè)置動(dòng)畫励翼。終點(diǎn)對(duì)應(yīng)于漸變的最后一個(gè)停止點(diǎn),該點(diǎn)在單位坐標(biāo)空間中定義辜荠,然后在繪制時(shí)映射到層的邊界矩形汽抚。默認(rèn)值為(0.5,1.0)。

@property(nullable, copy) NSArray *colors;

函數(shù)描述:CGColorRef對(duì)象的數(shù)組伯病,定義每個(gè)漸變停止點(diǎn)的顏色殊橙。數(shù)組中只設(shè)置一個(gè)顏色是不顯示的∮樱可設(shè)置動(dòng)畫膨蛮。

@property(copy) CAGradientLayerType type;

函數(shù)描述圖層繪制漸變時(shí)的樣式。默認(rèn)值為kCAGradientLayerAxial季研。

  • CAGradientLayerType列舉的樣式:
// 軸向梯度(也稱為線性梯度)沿兩個(gè)定義端點(diǎn)之間的軸變化敞葛,垂直于這條軸線上的線條中所有點(diǎn)都具有相同的顏色值。
CA_EXTERN CAGradientLayerType const kCAGradientLayerAxial
    API_AVAILABLE(macos(10.6), ios(3.0), watchos(2.0), tvos(9.0));
//徑向梯度与涡。漸變被定義為一個(gè)橢圓惹谐,它的中心是` startPoint `,寬度和高度定義為` (endPoint.x - startPoint.x) * 2 ` 和 `(endPoint.y - startPoint.y) * 2'驼卖。
//徑向梯度是沿兩個(gè)限定端之間的軸徑向變化的填充,其通常都是圓
CA_EXTERN CAGradientLayerType const kCAGradientLayerRadial
    API_AVAILABLE(macos(10.6), ios(3.2), watchos(2.0), tvos(9.0));
//錐形漸變氨肌。梯度以“startPoint”為中心,其0度方向由“startPoint”和“endPoint”之間的矢量定義酌畜。
//當(dāng)“startPoint”和“endPoint”重疊時(shí)怎囚,結(jié)果未定義。梯度的角度在正x軸朝向正y軸的旋轉(zhuǎn)方向上增加桥胞。
CA_EXTERN CAGradientLayerType const kCAGradientLayerConic
    API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0));

\color{red}{例如設(shè)置視圖背景漸變色的代碼示例:}

- (void)setGradualChangeColorView:(UIView *)view{
    
    //CAGradientLayer繼承CALayer恳守,可以設(shè)置漸變圖層
    CAGradientLayer *grandientLayer = [[CAGradientLayer alloc] init];
    grandientLayer.frame = view.bounds;
    [view.layer addSublayer:grandientLayer];
    [view.layer insertSublayer:grandientLayer atIndex:0];
    //設(shè)置漸變的方向 左上(0,0)  右下(1,1)
    grandientLayer.startPoint = CGPointZero;
    grandientLayer.endPoint = CGPointMake(0.0, 1.0);
    //colors漸變的顏色數(shù)組 這個(gè)數(shù)組中只設(shè)置一個(gè)顏色是不顯示的
    grandientLayer.colors = @[(id)[UIColor redColor].CGColor, (id)[UIColor greenColor].CGColor];
    grandientLayer.type = kCAGradientLayerAxial;
    
}
- (void)viewDidLoad {

    [super viewDidLoad];
    UIView *view = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetMidX(self.view.frame) - 50, CGRectGetMidY(self.view.frame) - 50, 100, 100)];
    [self.view addSubview:view];
    [self setGradualChangeColorView:view];
  
}
屏幕快照 2019-10-30 下午10.50.18.png

CAReplicatorLayer -- 復(fù)制層

CAReplicatorLayer繼承自CALayer,是一個(gè)Layer容器贩虾,添加到容器上的子Layer可以復(fù)制若干份催烘,可以設(shè)定子Layer復(fù)制份數(shù)、設(shè)定副本之間的距離缎罢、透明度伊群、顏色考杉、旋轉(zhuǎn)、位置等舰始,可以使用CAReplicatorLayer對(duì)象來基于單一源層構(gòu)建復(fù)雜的布局崇棠。

CAReplicatorLayer的屬性
@property CFTimeInterval instanceDelay;

屬性描述指定復(fù)制每個(gè)圖層副本之間的延遲(以秒為單位),可設(shè)置動(dòng)畫蔽午,默認(rèn)值為0.0易茬,這意味著添加到被復(fù)制出的圖層副本上的任何動(dòng)畫都將同步酬蹋。

@property NSInteger instanceCount;

屬性描述要通過復(fù)制創(chuàng)建的圖層副本數(shù)量及老,其中包括源圖層,默認(rèn)值為1范抓,不創(chuàng)建額外圖層副本骄恶。

@property CATransform3D instanceTransform;

屬性描述通過對(duì)前一實(shí)例的矩陣轉(zhuǎn)換來生成當(dāng)前實(shí)例,可以做成動(dòng)畫匕垫,轉(zhuǎn)換的矩陣相對(duì)于該圖層中心的位置應(yīng)用僧鲁,默認(rèn)是單位矩陣。

@property BOOL preservesDepth;

屬性描述定義此層是否將其子層展平到其平面中象泵。如果YES寞秃,則該層的行為與CATTransfermLayer相似,并且具有相同的限制偶惠,默認(rèn)值為NO春寿。

@property(nullable) CGColorRef instanceColor;

屬性描述定義源圖層對(duì)象的顏色,可以做成動(dòng)畫忽孽,默認(rèn)為不透明白色绑改。

@property float instanceRedOffset;

屬性描述定義添加到每個(gè)復(fù)制實(shí)例的顏色的紅色分量的偏移量,可設(shè)置動(dòng)畫兄一,通過對(duì)前一實(shí)例顏色的紅色分量添加instanceRedOffset以生成當(dāng)前實(shí)例的調(diào)制顏色厘线。

@property float instanceGreenOffset;

屬性描述定義添加到每個(gè)復(fù)制實(shí)例的顏色的綠色分量的偏移量,可設(shè)置動(dòng)畫出革,通過對(duì)前一實(shí)例顏色的綠色分量添加instanceGreenOffset以生成當(dāng)前實(shí)例的調(diào)制顏色造壮。

@property float instanceBlueOffset;

屬性描述定義添加到每個(gè)復(fù)制實(shí)例的顏色的藍(lán)色分量的偏移量,可設(shè)置動(dòng)畫骂束,通過對(duì)前一實(shí)例顏色的藍(lán)色分量添加instanceBlueOffset以生成當(dāng)前實(shí)例的調(diào)制顏色费薄。

@property float instanceAlphaOffset;

屬性描述定義添加到每個(gè)復(fù)制實(shí)例的顏色的透明度分量的偏移量,可設(shè)置動(dòng)畫栖雾,通過對(duì)前一實(shí)例顏色的透明度分量添加instanceAlphaOffset以生成當(dāng)前實(shí)例的調(diào)制顏色楞抡。

\color{red}{文檔中提供的簡(jiǎn)單示例:}

創(chuàng)建一個(gè)網(wǎng)格,第一行五個(gè)正方形顏色從白色漸變?yōu)榧t色析藕,垂直方向上每個(gè)正方形紅色偏移量值逐漸減小 :

- (void)viewDidLoad {
    [super viewDidLoad];
    //初始化紅色方塊層對(duì)象
    CALayer *redSquare = [CALayer layer];
    redSquare.backgroundColor = [UIColor whiteColor].CGColor;
    redSquare.borderWidth = 1.0;
    redSquare.borderColor = [UIColor greenColor].CGColor;
    redSquare.frame = CGRectMake(0, 0, 25, 25);
    //初始化復(fù)制層對(duì)象
    CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
    //通過復(fù)制創(chuàng)建的圖層副本數(shù)
    NSInteger instanceCount = 5;
    replicatorLayer.instanceCount = instanceCount;
    //通過對(duì)前一實(shí)例的矩陣轉(zhuǎn)換來生成當(dāng)前實(shí)例
    replicatorLayer.instanceTransform = CATransform3DMakeTranslation(50, 0, 0);
    //設(shè)置顏色分量偏移量
    CGFloat offsetStep = -1.0 / instanceCount;
    replicatorLayer.instanceBlueOffset = offsetStep;
    replicatorLayer.instanceGreenOffset = offsetStep;
    //添加紅色方塊層對(duì)象到復(fù)制層
    [replicatorLayer addSublayer:redSquare];
    //初始化外層復(fù)制層對(duì)象
    CAReplicatorLayer *outerReplicatorLayer = [CAReplicatorLayer layer];
    //嵌套復(fù)制層
    [outerReplicatorLayer addSublayer:replicatorLayer];
    //通過復(fù)制創(chuàng)建的圖層副本數(shù)
    outerReplicatorLayer.instanceCount = instanceCount;
    //通過對(duì)前一實(shí)例的矩陣轉(zhuǎn)換來生成當(dāng)前實(shí)例
    outerReplicatorLayer.instanceTransform = CATransform3DMakeTranslation(0, 110, 0);
    //設(shè)置顏色分量偏移量
    outerReplicatorLayer.instanceRedOffset = offsetStep;
    //顯示外層復(fù)制層對(duì)象
    outerReplicatorLayer.position = CGPointMake(0, 200);
    [self.view.layer addSublayer:outerReplicatorLayer];
}

截屏2022-07-27 15.41.48.png

\color{red}{旋轉(zhuǎn)的圓圈:}

- (void)viewDidLoad {
    [super viewDidLoad];
    //初始化圓點(diǎn)圖層
    CALayer *circle = [CALayer layer];
    circle.frame = CGRectMake(0, 0, 10, 10);
    circle.backgroundColor = UIColor.blueColor.CGColor;
    circle.cornerRadius = 5;
    circle.position = CGPointMake(0, 50);
    //圓點(diǎn)圖層上的透明度動(dòng)畫
    CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"];
    fadeOut.fromValue = @(1);
    fadeOut.toValue = @(0);
    fadeOut.duration = 1;
    fadeOut.repeatCount = CGFLOAT_MAX;
    [circle addAnimation:fadeOut forKey:nil];
    //復(fù)制層
    CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
    //添加圓點(diǎn)圖層到復(fù)制層
    [replicatorLayer addSublayer:circle];
    //通過復(fù)制創(chuàng)建的圖層副本數(shù)
    NSNumber *instanceCount = @(30);
    replicatorLayer.instanceCount = instanceCount.integerValue;
    //指定復(fù)制每個(gè)圖層副本之間的延遲
    replicatorLayer.instanceDelay = fadeOut.duration / instanceCount.doubleValue;
    //過對(duì)前一實(shí)例的矩陣轉(zhuǎn)換來生成當(dāng)前實(shí)例
    CGFloat angle = -M_PI * 2 / instanceCount.floatValue;
    replicatorLayer.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1);
    //顯示復(fù)制層對(duì)象
    replicatorLayer.frame = CGRectMake(CGRectGetMidX(self.view.frame) - 50, CGRectGetMidY(self.view.frame) - 50, 100, 100);
    [self.view.layer addSublayer:replicatorLayer];
}
Jietu20220727-154855-HD.gif

\color{red}{簡(jiǎn)單的震動(dòng)條示例:}

@interface TestCodeController ()

@end

@implementation TestCodeController

- (void)viewDidLoad {

    [super viewDidLoad];
    
    UIView *aniView = [[UIView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width / 2 - 40, CGRectGetMidY(self.view.frame) , 5, 20)];
    [self.view addSubview:aniView];
    [aniView.layer addSublayer: [self replicatorLayer_Shake]];

}

// 震動(dòng)條動(dòng)畫
- (CALayer *)replicatorLayer_Shake{
    //初始化層對(duì)象
    CALayer *layer = [[CALayer alloc]init];
    //層對(duì)象框架矩形
    layer.frame = CGRectMake(0, 0, 10, 32);
    //設(shè)置圓角
    layer.cornerRadius = 5.0f;
    //設(shè)置層背景色
    layer.backgroundColor = [UIColor redColor].CGColor;
    //定義層邊界矩形的定位點(diǎn)召廷,可設(shè)置動(dòng)畫
    layer.anchorPoint = CGPointMake(0.5, 0.5);
    // 添加一個(gè)對(duì)Y方向進(jìn)行縮放的基本動(dòng)畫
    [layer addAnimation:[self scaleYAnimation] forKey:@"scaleAnimation"];
    
    //初始化復(fù)制層
    CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
    //復(fù)制層框架矩形
    replicatorLayer.frame = CGRectMake(0, 0, 80, 80);
    //要?jiǎng)?chuàng)建的副本數(shù)
    replicatorLayer.instanceCount = 3;
    //復(fù)制矩陣
    replicatorLayer.instanceTransform =  CATransform3DMakeTranslation(20, 0, 0);
    //指定復(fù)制副本之間的延遲(秒)
    replicatorLayer.instanceDelay = 0.2;
    //為每個(gè)復(fù)制的實(shí)例定義添加到組件的顏色的綠色偏移量,可設(shè)置動(dòng)畫
    replicatorLayer.instanceGreenOffset = 10;
    //將層對(duì)象添加到復(fù)制層容器
    [replicatorLayer addSublayer:layer];
    //返回復(fù)制層容器
    return replicatorLayer;
}

//對(duì)Y方向進(jìn)行縮放的基本動(dòng)畫
- (CABasicAnimation *)scaleYAnimation{
    //對(duì)Y方向進(jìn)行縮放的基本動(dòng)畫
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
    //縮放結(jié)束值
    anim.toValue = @0.1;
    //動(dòng)畫持續(xù)時(shí)間
    anim.duration = 0.4;
    //動(dòng)畫完成后是否在層中移除
    anim.removedOnCompletion = NO;
    //動(dòng)畫結(jié)束是否執(zhí)行逆動(dòng)畫
    anim.autoreverses = YES;
    //動(dòng)畫重復(fù)次數(shù)為無(wú)限重復(fù)
    anim.repeatCount = MAXFLOAT;
    //返回/對(duì)Y方向進(jìn)行縮放的基本動(dòng)畫
    return anim;
}

@end

效果如圖:

Jietu20200924-162759.gif

CAAnimation - 動(dòng)畫的抽象超類

CAAnimation蔬芥,核心動(dòng)畫中動(dòng)畫的抽象超類常遂。繼承自NSObject掰吕,遵循了NSSecureCoding银亲、 NSCopying,先煎、CAMediaTiming,助泽、CAAction協(xié)議楞慈,CAAnimation為CAMediaTiming和CAAction協(xié)議提供了基本的支持旺嬉。不要?jiǎng)?chuàng)建CAAnimation實(shí)例:要使核心動(dòng)畫層或SceneKit對(duì)象具有動(dòng)畫效果败潦,請(qǐng)創(chuàng)建具體子類CABasicAnimation本冲、CAKeyframeAnimation、CAAnimationGroup或CATransition的實(shí)例劫扒。

CAAnimation提供的屬性
@property(nullable, strong) CAMediaTimingFunction *timingFunction;

屬性描述一個(gè)可選的計(jì)時(shí)函數(shù)檬洞,用來定義動(dòng)畫的節(jié)奏。默認(rèn)為nil沟饥,表示線性節(jié)奏添怔。

@property(nullable, strong) id <CAAnimationDelegate> delegate;

屬性描述指定調(diào)用方的代理對(duì)象,代理對(duì)象由調(diào)用方保留贤旷。CAAnimation的實(shí)例不應(yīng)該被設(shè)置為它自己的代理广料,這樣做將導(dǎo)致保留周期。

@property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;

屬性描述確定動(dòng)畫是否在完成時(shí)從目標(biāo)圖層的動(dòng)畫中移除幼驶。如果為“YES”艾杏,動(dòng)畫將在其活動(dòng)持續(xù)時(shí)間過后從目標(biāo)圖層的動(dòng)畫中移除。默認(rèn)為“YES”县遣。

CAAnimation提供的函數(shù)
+ (instancetype)animation;

函數(shù)描述 : 創(chuàng)建并返回一個(gè)新的CAAnimation實(shí)例糜颠。

+ (nullable id)defaultValueForKey:(NSString *)key;

屬性描述 : 使用指定鍵指定調(diào)用方屬性的默認(rèn)值。如果此方法返回nil萧求,則根據(jù)鍵的聲明類型為屬性提供一個(gè)合適的“zero”默認(rèn)值其兴。例如,如果key是CGSize對(duì)象夸政,則返回大小為(0.0,0.0)的值元旬;對(duì)于CGRect,返回一個(gè)空矩形守问;對(duì)于CGAffineTransform和CATransform3D匀归,返回適當(dāng)?shù)膯挝痪仃嚒?/p>

參數(shù) :

key :調(diào)用方屬性之一的名稱。

返回值 :

指定屬性的默認(rèn)值耗帕,如果沒有設(shè)置默認(rèn)值穆端,則返回nil。

- (BOOL)shouldArchiveValueForKey:(NSString *)key;

屬性描述指定是否要?dú)w檔給定鍵的屬性值仿便。由對(duì)象的實(shí)現(xiàn)encodeWithCoder:調(diào)用体啰,對(duì)象必須實(shí)現(xiàn)鍵歸檔攒巍,默認(rèn)實(shí)現(xiàn)返回YES。

參數(shù) :

key : 調(diào)用方屬性之一的名稱荒勇。

返回值 :

如果要?dú)w檔指定的屬性柒莉,則為“YES”,否則為“NO”沽翔。

CAAnimation提供的代理函數(shù)
- (void)animationDidStart:(CAAnimation *)anim;

函數(shù)描述 : 通知代理動(dòng)畫已開始兢孝。

參數(shù) :

anim : 已啟動(dòng)的CAAnimation對(duì)象。

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

函數(shù)描述 :通知代理動(dòng)畫已結(jié)束仅偎。動(dòng)畫結(jié)束的原因可能是已達(dá)到動(dòng)畫活動(dòng)持續(xù)時(shí)間跨蟹,或者動(dòng)畫在其附著的圖層中被移除,如果動(dòng)畫因?yàn)檫_(dá)到其活動(dòng)持續(xù)時(shí)間后而結(jié)束哨颂,flag為YES喷市。

參數(shù) :

anim :結(jié)束的動(dòng)畫對(duì)象相种。

flag : 指示動(dòng)畫是否因?yàn)檫_(dá)到其活動(dòng)持續(xù)時(shí)間后而結(jié)束的標(biāo)志威恼。

CAMediaTiming協(xié)議

CAMediaTiming協(xié)議建模了一個(gè)分層計(jì)時(shí)系統(tǒng),CALayer與CAAnimation 都實(shí)現(xiàn)了該協(xié)議寝并,協(xié)議中定義了在一段動(dòng)畫內(nèi)用來控制時(shí)間的屬性的集合箫措。

@property CFTimeInterval duration;

屬性描述指定動(dòng)畫每執(zhí)行一次的基本持續(xù)時(shí)間(秒),默認(rèn)為值為0衬潦,但仍舊有0.25秒的動(dòng)畫斤蔓。

@property float speed;

屬性描述相對(duì)于duration所設(shè)置時(shí)間的流逝倍速,值越大則duration所設(shè)置的流逝時(shí)間越快镀岛。例如duration設(shè)置動(dòng)畫持續(xù)時(shí)間為10秒弦牡,speed設(shè)置為2.0,則5秒即完成動(dòng)畫漂羊。

@property CFTimeInterval timeOffset;

屬性描述時(shí)間偏移驾锰,動(dòng)畫會(huì)在設(shè)置的偏移秒數(shù)開始執(zhí)行,并執(zhí)行duration所設(shè)置的持續(xù)時(shí)間走越。例如duration設(shè)置動(dòng)畫持續(xù)時(shí)間為10秒椭豫,timeOffset設(shè)置為5.0,則動(dòng)畫在5秒處開始旨指,并運(yùn)行10秒赏酥。

@property float repeatCount;

屬性描述動(dòng)畫的重復(fù)次數(shù),如果repeatCount為0谆构,則忽略該屬性裸扶,默認(rèn)為0,將此屬性設(shè)置為HUGE_VALF將導(dǎo)致動(dòng)畫永遠(yuǎn)重復(fù)搬素。如果同時(shí)指定了repeatDuration和repeatCount呵晨,則行為未定義瞬项。

@property CFTimeInterval repeatDuration;

屬性描述動(dòng)畫將重復(fù)執(zhí)行的時(shí)間(秒),如果小于duration所設(shè)置時(shí)間何荚,則動(dòng)畫只執(zhí)行repeatDuration所設(shè)置時(shí)間(秒)的部分囱淋,如果大于duration所設(shè)置時(shí)間,動(dòng)畫將重復(fù)執(zhí)行repeatDuration超出duration所設(shè)置時(shí)間的部分餐塘。該屬性不受speed屬性的影響妥衣,且與repeatDuration屬性沖突。為0則忽略該屬性戒傻,默認(rèn)為0税手。

@property BOOL autoreverses;

屬性描述動(dòng)畫在執(zhí)行一次后是否執(zhí)行逆動(dòng)畫,如果為YES需纳,動(dòng)畫在正向執(zhí)行一次后芦倒,反向執(zhí)行一次。默認(rèn)為NO不翩。

@property(copy) CAMediaTimingFillMode fillMode;

屬性描述指定動(dòng)畫開始之前與結(jié)束之后對(duì)動(dòng)畫時(shí)間上的一種填充兵扬,默認(rèn)值為kCAFillModeRemoved,可選值如下:

//當(dāng)動(dòng)畫完成時(shí)口蝠,以最終的可見狀態(tài)作為填充
CA_EXTERN CAMediaTimingFillMode const kCAFillModeForwards
    API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
//動(dòng)畫開始之前器钟,以動(dòng)畫的第一幀作為填充
CA_EXTERN CAMediaTimingFillMode const kCAFillModeBackwards
    API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
//結(jié)合kCAFillModeForwards與kCAFillModeBackwards,即以最終的可見狀態(tài)填充動(dòng)畫完成時(shí)妙蔗,以動(dòng)畫的第一幀填充動(dòng)畫開始之前
CA_EXTERN CAMediaTimingFillMode const kCAFillModeBoth
    API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
//動(dòng)畫完成后將移除傲霸,無(wú)填充
CA_EXTERN CAMediaTimingFillMode const kCAFillModeRemoved
    API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property CFTimeInterval beginTime;

屬性描述如果適用,指定相對(duì)于其父對(duì)象的開始時(shí)間(延遲時(shí)間)眉反。例如在動(dòng)畫在CAAnimationGroup動(dòng)畫組中昙啄,那么動(dòng)畫的開始時(shí)間是相對(duì)于CAAnimationGroup動(dòng)畫組動(dòng)畫開始的延遲,如果直接添加在CALayer(圖層)中寸五,則需要獲取CALayer(圖層)被添加的時(shí)間后梳凛,根據(jù)CALayer(圖層)被添加的時(shí)間設(shè)置延遲。

CATransition - 轉(zhuǎn)場(chǎng)動(dòng)畫

CATransition繼承自CAAnimation播歼,在圖層狀態(tài)之間提供動(dòng)畫轉(zhuǎn)換的對(duì)象伶跷。通過創(chuàng)建并向?qū)又刑砑覥ATransition對(duì)象,可以在圖層的狀態(tài)之間進(jìn)行轉(zhuǎn)換秘狞,默認(rèn)過渡是交叉淡入叭莫,但可以指定與一組預(yù)定義過渡不同的效果。

CATransition提供的屬性
@property(copy) CATransitionType type;

屬性描述指定預(yù)定義的轉(zhuǎn)換類型烁试」统酰可能的值以常見的轉(zhuǎn)換類型顯示。如果在篩選器屬性中指定了自定義轉(zhuǎn)換减响,則忽略此屬性靖诗。默認(rèn)值為kCATransitionFade郭怪。

//當(dāng)圖層變得可見或隱藏時(shí),其內(nèi)容將逐漸消失刊橘。
CA_EXTERN CATransitionType const kCATransitionFade
//該層的內(nèi)容在任何現(xiàn)有內(nèi)容上滑動(dòng)到位鄙才。公共轉(zhuǎn)換子類型用于此轉(zhuǎn)換。
CA_EXTERN CATransitionType const kCATransitionMoveIn
//該層的內(nèi)容推動(dòng)任何現(xiàn)有內(nèi)容促绵,因?yàn)樗瑒?dòng)到位攒庵。公共轉(zhuǎn)換子類型用于此轉(zhuǎn)換。
CA_EXTERN CATransitionType const kCATransitionPush
//層的內(nèi)容按轉(zhuǎn)換子類型指定的方向逐漸顯示败晴。公共轉(zhuǎn)換子類型用于此轉(zhuǎn)換浓冒。
CA_EXTERN CATransitionType const kCATransitionReveal
@property(nullable, copy) CATransitionSubtype subtype;

屬性描述指定一個(gè)可選子類型,該子類型預(yù)定義了基于運(yùn)動(dòng)的變換方向尖坤∥壤粒可能的值顯示在公共轉(zhuǎn)換子類型中,默認(rèn)值為nil慢味。

//過渡從層的右側(cè)開始场梆。
CA_EXTERN CATransitionSubtype const kCATransitionFromRight
//過渡從層的左側(cè)開始。
CA_EXTERN CATransitionSubtype const kCATransitionFromLeft
//過渡從層的頂部開始贮缕。
CA_EXTERN CATransitionSubtype const kCATransitionFromTop
//過渡從層的底部開始辙谜。
CA_EXTERN CATransitionSubtype const kCATransitionFromBottom
@property float startProgress;

屬性描述指示調(diào)用方的起點(diǎn)俺榆,作為整個(gè)轉(zhuǎn)換的一部分感昼,合法值是介于0.0和1.0之間的數(shù)字。例如罐脊,要在轉(zhuǎn)換過程的一半開始定嗓,請(qǐng)將startProgress設(shè)置為0.5。默認(rèn)值為0萍桌。

@property float endProgress;

屬性描述指示調(diào)用方的終點(diǎn)宵溅,作為整個(gè)轉(zhuǎn)換的一部分,該值必須大于或等于startProgress上炎,且不大于1.0恃逻。如果endProgress小于startProgress,則行為未定義藕施。默認(rèn)值是1.0寇损。

\color{red}{CATransition簡(jiǎn)單的代碼示例:}

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    UIButton *transitionBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [transitionBtn setTitle:@"轉(zhuǎn)場(chǎng)動(dòng)畫" forState:UIControlStateNormal];
    [transitionBtn setBackgroundColor:[UIColor blueColor]];
    transitionBtn.titleLabel.font = [UIFont systemFontOfSize:15];
    [transitionBtn addTarget:self action:@selector(transitionBtnClick) forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:transitionBtn];
    [transitionBtn mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view).offset(100);
        make.centerX.equalTo(self.view);
        make.size.mas_equalTo(CGSizeMake(75, 35));
    }];
    
}

//轉(zhuǎn)場(chǎng)動(dòng)畫按鈕點(diǎn)擊
- (void)transitionBtnClick{
    
    UIView *view = [[UIView alloc]initWithFrame:CGRectZero];
    view.backgroundColor = [UIColor redColor];
    
    CATransition *animation = [CATransition animation];
    animation.delegate = self;
    //動(dòng)畫持續(xù)時(shí)間
    animation.duration = 0.4;
    //減緩速度,這會(huì)導(dǎo)致動(dòng)畫快速開始裳食,然后隨著它的進(jìn)展而緩慢矛市。
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    //動(dòng)畫為推出類型
    animation.type = kCATransitionPush;
    //方向,向上方推出
    animation.subtype = kCATransitionFromTop;
    //添加動(dòng)畫
    [view.layer addAnimation:animation forKey:@"animation1"];
    //布局視圖
    [self.view addSubview:view];
    [view mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.view.mas_bottom);
        make.size.mas_equalTo(CGSizeMake(SCREEN_WIDTH, 360));
    }];
    
}

簡(jiǎn)單的推出效果 :


Jietu20200104-152550.gif

CAAnimationGroup - 分組動(dòng)畫

CAAnimationGroup繼承自CAAnimation诲祸,允許多個(gè)動(dòng)畫被分組并同時(shí)運(yùn)行的對(duì)象浊吏。分組中添加的動(dòng)畫會(huì)在CAAnimationGroup實(shí)例指定的時(shí)間空間中運(yùn)行而昨,分組中添加的動(dòng)畫時(shí)間如果超過CAAnimationGroup實(shí)例設(shè)置的動(dòng)畫持續(xù)時(shí)間,則添加的動(dòng)畫被剪切到動(dòng)畫組的持續(xù)時(shí)間找田。例如歌憨,在動(dòng)畫組中添加的動(dòng)畫持續(xù)時(shí)間10秒,但CAAnimationGroup實(shí)例設(shè)置的持續(xù)時(shí)間為5秒墩衙,則只顯示動(dòng)畫的前5秒躺孝。

動(dòng)畫數(shù)組中添加的動(dòng)畫其設(shè)置的代理和removedOnCompletion屬性目前會(huì)被忽略。由CAAnimationGroup的代理接收這些消息底桂。

CAAnimationGroup提供的屬性

@property(nullable, copy) NSArray<CAAnimation *> *animations;

屬性描述 : 要在調(diào)用方的時(shí)間空間內(nèi)計(jì)算的一組CAAnimation對(duì)象植袍。動(dòng)畫同時(shí)在接收方的時(shí)間空間中運(yùn)行。

@property(nullable, copy) NSArray<CAAnimation *> *animations;

\color{red}{CAAnimationGroup簡(jiǎn)單的代碼示例:}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.backgroundColor = [UIColor blueColor];
    [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [button.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
    ]];
    
    self.myView = [[MyView alloc]initWithFrame:CGRectZero];
    self.myView.layer.contents = (id)[UIImage imageNamed:@"darts"].CGImage;
    [self.view addSubview:self.myView];
    self.myView.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [self.myView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
        [self.myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
        [self.myView.widthAnchor constraintEqualToConstant:100],
        [self.myView.heightAnchor constraintEqualToConstant:100],
    ]];
}

- (void)buttonClick:(UIButton *)sender {
    
    CABasicAnimation * rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    rotateAnimation.fromValue = [NSNumber numberWithFloat:0];
    rotateAnimation.toValue = [NSNumber numberWithFloat:M_PI * 2 + M_LN2];
    rotateAnimation.duration = 0.25f;
    rotateAnimation.repeatCount = HUGE_VALF;
    rotateAnimation.beginTime = 1.0f;
    
    CAKeyframeAnimation* frameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"];
    frameAnimation.values = @[@50,@(UIScreen.mainScreen.bounds.size.width - 50)];
    frameAnimation.keyTimes = @[@0,@1];

    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.animations = @[rotateAnimation,frameAnimation];
    group.duration = 5.0f;
    group.fillMode = kCAFillModeForwards;
    group.removedOnCompletion = NO;
    [self.myView.layer addAnimation:group forKey:nil];
}

旋轉(zhuǎn)加移動(dòng) :

Jietu20220713-171323-HD.gif

CAPropertyAnimation - 屬性動(dòng)畫

繼承自CAAnimation籽懦,是CAAnimation的一個(gè)抽象子類于个,用于創(chuàng)建操作圖層屬性值的動(dòng)畫,通常不直接使用暮顺,而是使用其子類CABasicAnimation或CAKeyframeAnimation厅篓。

CAPropertyAnimation提供的屬性
@property(nullable, copy) NSString *keyPath;

屬性描述對(duì)某個(gè)屬性需要設(shè)置動(dòng)畫的字符串描述,例如使用這一字符串@"position.x"描述動(dòng)畫在CGPoint中心點(diǎn)X軸方向改變位置捶码。

@property(getter=isAdditive) BOOL additive;

屬性描述 : 在動(dòng)畫每次執(zhí)行后羽氮,是否將動(dòng)畫指定的值添加到當(dāng)前渲染樹中的值以生成新的渲染樹值,如果為YES惫恼,動(dòng)畫指定的值將會(huì)添加到屬性的當(dāng)前渲染樹值中档押,以生成新的渲染樹值。例如在keypath為@"position.x"描述的動(dòng)畫中祈纯,該屬性為YES時(shí)令宿,position.x += value,該屬性為NO時(shí)腕窥,position.x = value粒没。該屬性默認(rèn)為NO。(注:在動(dòng)畫設(shè)置重復(fù)執(zhí)行時(shí)簇爆,在重復(fù)的過程中癞松,該值為YES,值也不會(huì)在動(dòng)畫重復(fù)過程中累加)

例如在下面的代碼中入蛆,可以比較直觀的觀察additive屬性變化的不同效果:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.backgroundColor = [UIColor blueColor];
    [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [button.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
    ]];
    
    self.myView = [[MyView alloc]initWithFrame:CGRectZero];
    self.myView.layer.contents = (id)[UIImage imageNamed:@"darts"].CGImage;
    [self.view addSubview:self.myView];
    self.myView.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [self.myView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
        [self.myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
        [self.myView.widthAnchor constraintEqualToConstant:100],
        [self.myView.heightAnchor constraintEqualToConstant:100],
    ]];
}

- (void)buttonClick:(UIButton *)sender {
    CABasicAnimation * rotateAnimation = [CABasicAnimation animationWithKeyPath:@"position.x"];
    rotateAnimation.fromValue = @(50);
    rotateAnimation.toValue = @(100);
    rotateAnimation.duration = 1.0f;
    rotateAnimation.repeatCount = 1;
    rotateAnimation.fillMode = kCAFillModeForwards;
    rotateAnimation.removedOnCompletion = NO;
    rotateAnimation.additive = YES;
    [self.myView.layer addAnimation:rotateAnimation forKey:nil];
}

當(dāng)additive為YES時(shí)响蓉,點(diǎn)擊執(zhí)行三次動(dòng)畫:

Jietu20220714-140139-HD.gif

當(dāng)additive為NO時(shí),點(diǎn)擊執(zhí)行三次動(dòng)畫:

Jietu20220714-140253-HD.gif
@property(getter=isCumulative) BOOL cumulative;

屬性描述 : cumulative屬性影響重復(fù)動(dòng)畫生成結(jié)果的方式安寺。如果為YES厕妖,則動(dòng)畫的當(dāng)前值是上一個(gè)重復(fù)周期結(jié)束時(shí)的值,加上當(dāng)前重復(fù)周期的值挑庶。如果為NO言秸,則該值只是為當(dāng)前重復(fù)周期計(jì)算的值软能。默認(rèn)為NO。與additive效果類似举畸,不過該屬性是作用在動(dòng)畫重復(fù)過程中的查排。

@property(nullable, strong) CAValueFunction *valueFunction;

屬性描述 : 如果為非nil值,則定義了為目標(biāo)屬性插入新值的動(dòng)畫方式的函數(shù)抄沮,默認(rèn)為nil跋核。valueFunction是專門為了transform動(dòng)畫而設(shè)置的,包括旋轉(zhuǎn)叛买、縮放砂代、平移等。

\color{red}{例如在X軸線方向平移 :}

- (void)buttonClick:(UIButton *)sender {
    
    CABasicAnimation * rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    rotateAnimation.fromValue = [NSNumber numberWithFloat:0];
    rotateAnimation.toValue = [NSNumber numberWithFloat:100];
    rotateAnimation.duration = 1.0f;
    rotateAnimation.repeatCount = HUGE_VALF;
    rotateAnimation.valueFunction = [CAValueFunction functionWithName:kCAValueFunctionTranslateX];
    [self.myView.layer addAnimation:rotateAnimation forKey:nil];
}
CAPropertyAnimation提供的函數(shù)
+ (instancetype)animationWithKeyPath:(nullable NSString *)path;

函數(shù)描述使用指定的path描述的屬性創(chuàng)建CAPropertyAnimation實(shí)例率挣,例如使用這一字符串@"position.x"創(chuàng)建CGPoint中心點(diǎn)X軸方向改變位置的CAPropertyAnimation實(shí)例刻伊。

參數(shù) :

path : 描述屬性的字符串。

返回值 : CAPropertyAnimation實(shí)例椒功,并且該實(shí)例的keyPath設(shè)置為path捶箱。

CAKeyframeAnimation - 關(guān)鍵幀動(dòng)畫

CAKeyframeAnimation繼承自CAPropertyAnimation,為CALayer(圖層)對(duì)象提供關(guān)鍵幀動(dòng)畫功能的對(duì)象(在某一時(shí)間段動(dòng)畫進(jìn)行到某一幀)动漾。使用繼承的animationWithKeyPath:方法創(chuàng)建CAKeyframeAnimation對(duì)象非洲,keyPath指定要在圖層上進(jìn)行動(dòng)畫的圖層框架屬性酒唉,然后可以通過指定values和動(dòng)畫計(jì)時(shí)(例如keyTimes)控制動(dòng)畫行為蜜暑。

在動(dòng)畫過程中画恰,Core animation通過插入提供的值來生成中間值,例如當(dāng)為一個(gè)坐標(biāo)點(diǎn)(比如圖層的位置)設(shè)置動(dòng)畫時(shí)键思,可以為這個(gè)點(diǎn)指定一條由values構(gòu)成的路徑础爬,而不是單獨(dú)的值。動(dòng)畫的速度由提供的時(shí)間信息控制吼鳞。

CAKeyframeAnimation提供的屬性
@property(nullable, copy) NSArray *values;

屬性描述為CAKeyframeAnimation實(shí)例提供動(dòng)畫功能值的對(duì)象數(shù)組。values表示CAKeyframeAnimation實(shí)例動(dòng)畫必須通過的值叫搁。將給定的values中的值應(yīng)用到添加動(dòng)畫的圖層的時(shí)間取決于動(dòng)畫計(jì)時(shí)赔桌,動(dòng)畫計(jì)時(shí)由calculationMode、keyTimes和timingFunctions屬性控制渴逻。應(yīng)用于CAKeyframeAnimation實(shí)例之間的值是使用插值創(chuàng)建的疾党,除非計(jì)算模式設(shè)置為kCAAnimationDiscrete。

根據(jù)屬性的類型惨奕,可能需要用NSNumber的NSValue對(duì)象包裝這個(gè)數(shù)組中的值雪位。對(duì)于某些核心圖形數(shù)據(jù)類型,可能還需要在將它們添加到數(shù)組之前將它們轉(zhuǎn)換為id梨撞。

此屬性中的值僅在path屬性中的值為nil時(shí)使用雹洗。

@property(nullable) CGPathRef path;

屬性描述分配給此屬性的路徑對(duì)象定義了圖層屬性(圖層屬性包含 CGPoint 數(shù)據(jù)類型)在動(dòng)畫長(zhǎng)度上的值香罐。如果為此屬性指定值,則會(huì)忽略 values 屬性中的任何數(shù)據(jù)时肿。

為動(dòng)畫指定的任何計(jì)時(shí)值(keyTimes)都將應(yīng)用于用于創(chuàng)建路徑的點(diǎn)庇茫,路徑可以包含定義移動(dòng)到線段的點(diǎn)(moveToPoint:),以直線添加到線段的點(diǎn)或以曲線添加到線段的點(diǎn)螃成,直線段或曲線段會(huì)在線段的終點(diǎn)定義關(guān)鍵幀值旦签,然后在線段起點(diǎn)(前一條線段的終點(diǎn))與線段終點(diǎn)之間的所有其他的點(diǎn)進(jìn)行插值,以移動(dòng)的方式添加到線段的點(diǎn)不定義單獨(dú)的關(guān)鍵幀值寸宏。

動(dòng)畫沿路徑運(yùn)行的方式取決于calculationMode 屬性中的值宁炫。要實(shí)現(xiàn)沿路徑的平滑、勻速動(dòng)畫氮凝,請(qǐng)將calculationMode 屬性設(shè)置為kCAAnimationPaced 或kCAAnimationCubicPaced淋淀;要?jiǎng)?chuàng)建位置值從關(guān)鍵幀點(diǎn)跳轉(zhuǎn)到關(guān)鍵幀點(diǎn)(中間沒有插值)的動(dòng)畫,請(qǐng)使用 kCAAnimationDiscrete 值覆醇;要通過在點(diǎn)之間插值沿路徑設(shè)置動(dòng)畫朵纷,請(qǐng)使用kCAAnimationLinear值。

@property(copy) CAAnimationCalculationMode calculationMode;

屬性描述 :calculationMode可能的值有“discrete”永脓、“l(fā)inear”袍辞、“paced”、“cubic”和“cubicPaced”常摧。默認(rèn)為“ linear”搅吁。當(dāng)設(shè)置為paced或cubicPaced時(shí),動(dòng)畫的keyTimes和timingFunctions屬性將被忽略并隱式計(jì)算落午。

//關(guān)鍵幀值之間的簡(jiǎn)單線性計(jì)算谎懦。
CA_EXTERN CAAnimationCalculationMode const kCAAnimationLinear
//依次使用每個(gè)關(guān)鍵幀值,不計(jì)算插值溃斋。
CA_EXTERN CAAnimationCalculationMode const kCAAnimationDiscrete
//對(duì)線性關(guān)鍵幀值進(jìn)行插值以在整個(gè)動(dòng)畫中產(chǎn)生均勻的速度界拦。
CA_EXTERN CAAnimationCalculationMode const kCAAnimationPaced
//關(guān)鍵幀值之間的平滑樣條線計(jì)算。梗劫。
CA_EXTERN CAAnimationCalculationMode const kCAAnimationCubic
//對(duì)三次關(guān)鍵幀值進(jìn)行插值以在整個(gè)動(dòng)畫中產(chǎn)生均勻的速度享甸。
CA_EXTERN CAAnimationCalculationMode const kCAAnimationCubicPaced
@property(nullable, copy) NSArray<NSNumber *> *keyTimes;

屬性描述應(yīng)用于CAKeyframeAnimation實(shí)例動(dòng)畫的可選數(shù)組(數(shù)組中存放NSNumber對(duì)象),定義了動(dòng)畫的時(shí)間段梳侨,數(shù)組中的每個(gè)值是0.0(起始時(shí)間)到1.0(結(jié)束時(shí)間)之間的浮點(diǎn)數(shù)蛉威,數(shù)組中的每個(gè)后續(xù)值必須大于或等于前一個(gè)值,這些值代表在動(dòng)畫總持續(xù)時(shí)間中的一個(gè)時(shí)間點(diǎn)走哺。通常蚯嫌,數(shù)組中的元素?cái)?shù)量應(yīng)與values屬性中的元素?cái)?shù)量或path屬性中的控制點(diǎn)數(shù)量匹配,如果它們之間是不匹配的,則動(dòng)畫的效果可能不是所期望的择示。

如何在數(shù)組中包含適當(dāng)?shù)闹等Q于calculationMode屬性:

  • 如果calculationMode設(shè)置為kCAAnimationLinear或kCAAnimationCubic束凑,則數(shù)組中的第一個(gè)值必須是0.0,最后一個(gè)值必須是1.0对妄,所有中間值表示開始和結(jié)束時(shí)間之間的時(shí)間點(diǎn)湘今。

  • 如果calculationMode設(shè)置為kCAAnimationDiscrete,則數(shù)組中的第一個(gè)值必須是0.0剪菱,最后一個(gè)值必須是1.0摩瞎,數(shù)組中應(yīng)該比values數(shù)組中多一個(gè)條目。例如孝常,如果values數(shù)組中有兩個(gè)值旗们,那么該有三個(gè)時(shí)間點(diǎn)的值。

  • 如果calculationMode設(shè)置為kCAAnimationPaced或kCAAnimationCubicPaced构灸,則忽略此屬性中的值上渴。

如果此數(shù)組中的值無(wú)效或不適合當(dāng)前計(jì)算模式,則忽略它們喜颁。

@property(nullable, copy) NSArray<CAMediaTimingFunction *> *timingFunctions;

屬性描述應(yīng)用于CAKeyframeAnimation實(shí)例動(dòng)畫的可選數(shù)組(數(shù)組中存放CAMediaTimingFunction對(duì)象)稠氮,可以使用此數(shù)組定義values數(shù)組中兩個(gè)值節(jié)點(diǎn)之間的動(dòng)畫節(jié)奏,可以使動(dòng)畫線性過渡半开、或緩慢開始后加速過渡隔披、或加速開始后緩慢過渡。如果values屬性中的元素為n寂拆,則此數(shù)組中元素應(yīng)包含n-1個(gè)對(duì)象奢米。

此屬性通過動(dòng)畫計(jì)時(shí)控制動(dòng)畫節(jié)奏,如果在keyTimes屬性中提供了計(jì)時(shí)信息纠永,則此屬性指定的動(dòng)畫節(jié)奏計(jì)時(shí)將在keyTimes屬性提供的值之間進(jìn)行進(jìn)一步修改鬓长。如果未為keyTimes屬性指定值,則此屬性指定的動(dòng)畫節(jié)奏計(jì)時(shí)將修改動(dòng)畫對(duì)象提供的默認(rèn)計(jì)時(shí)尝江。

如果還在動(dòng)畫對(duì)象的timingFunction屬性中指定動(dòng)畫節(jié)奏計(jì)時(shí)函數(shù)涉波,則會(huì)首先應(yīng)用timingFunction屬性中指定的動(dòng)畫節(jié)奏計(jì)時(shí)函數(shù),然后應(yīng)用特定關(guān)鍵幀時(shí)間段的計(jì)時(shí)函數(shù)茂装。

@property(nullable, copy) CAAnimationRotationMode rotationMode;

屬性描述定義沿路徑設(shè)置動(dòng)畫的對(duì)象是否旋轉(zhuǎn)以匹配路徑切線怠蹂,默認(rèn)為nil,可以設(shè)置的值為“auto”和“autoReverse”少态。在為提供路徑對(duì)象時(shí)為此屬性設(shè)置值則行為是為定義的 。易遣。

CAAnimationRotationMode提供的值 :

//物體沿著與路徑相切的方向運(yùn)動(dòng)彼妻。
CA_EXTERN CAAnimationRotationMode const kCAAnimationRotateAuto
//物體以與路徑相切的180度移動(dòng)。
CA_EXTERN CAAnimationRotationMode const kCAAnimationRotateAutoReverse

\color{red}{CAKeyframeAnimation簡(jiǎn)單的代碼示例:}

通過values設(shè)置關(guān)鍵點(diǎn) :

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.backgroundColor = [UIColor blueColor];
    [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [button.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
    ]];
    
    self.myView = [[MyView alloc]initWithFrame:CGRectZero];
    self.myView.layer.contents = (id)[UIImage imageNamed:@"darts"].CGImage;
    [self.view addSubview:self.myView];
    self.myView.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [self.myView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [self.myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
        [self.myView.widthAnchor constraintEqualToConstant:100],
        [self.myView.heightAnchor constraintEqualToConstant:100],
    ]];
}

- (void)buttonClick:(UIButton *)sender {
    //獲取視圖的中心點(diǎn)X軸坐標(biāo)點(diǎn)
    CGFloat myViewCenterX = self.myView.center.x;
    //初始化在中心點(diǎn)在X軸坐標(biāo)移動(dòng)的關(guān)鍵幀動(dòng)畫
    CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"position.x"];
    //動(dòng)畫持續(xù)時(shí)間
    animation.duration = 5.0f;
    //動(dòng)畫的5個(gè)關(guān)鍵點(diǎn)
    animation.values = @[@(myViewCenterX),@(myViewCenterX - 150),@(myViewCenterX),@(myViewCenterX + 150),@(myViewCenterX)];
    //動(dòng)畫到達(dá)5個(gè)關(guān)鍵點(diǎn)的時(shí)間節(jié)點(diǎn)
    animation.keyTimes = @[@0,@0.25,@0.50,@0.75,@1];
    //在每?jī)蓚€(gè)時(shí)間節(jié)點(diǎn)之間的動(dòng)畫節(jié)奏
    animation.timingFunctions = @[
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    //添加動(dòng)畫
    [self.myView.layer addAnimation:animation forKey:nil];
}

代碼效果 :

Jietu20220715-172745-HD.gif

通過path設(shè)置路徑 :

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.backgroundColor = [UIColor blueColor];
    [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [button.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
    ]];
    
    self.myView = [[MyView alloc]initWithFrame:CGRectZero];
    self.myView.layer.contents = (id)[UIImage imageNamed:@"darts"].CGImage;
    [self.view addSubview:self.myView];
    self.myView.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [self.myView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [self.myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
        [self.myView.widthAnchor constraintEqualToConstant:100],
        [self.myView.heightAnchor constraintEqualToConstant:100],
    ]];
}

- (void)buttonClick:(UIButton *)sender {
    //曲線
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(CGRectGetMidX(self.view.frame) - 200 / 2, CGRectGetMidY(self.view.frame) - 150 / 2, 200, 150)];
    //形狀層
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    //路徑形狀填充顏色
    shapeLayer.fillColor = nil;
    //路徑的線寬
    shapeLayer.lineWidth = 2.5f;
    //路徑顏色
    shapeLayer.strokeColor = [UIColor blueColor].CGColor;
    //渲染的形狀的路徑
    shapeLayer.path = path.CGPath;
    //添加形狀層
    [self.view.layer addSublayer:shapeLayer];

    CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animation.path = path.CGPath;
    //動(dòng)畫持續(xù)時(shí)間
    animation.duration = 5.0f;
    //動(dòng)畫運(yùn)行方式
    animation.calculationMode = kCAAnimationCubicPaced;
    //動(dòng)畫重復(fù)次數(shù)
    animation.repeatCount = HUGE_VALF;
    //自動(dòng)旋轉(zhuǎn)匹配切線
    animation.rotationMode = kCAAnimationRotateAuto;
    //添加動(dòng)畫
    [self.myView.layer addAnimation:animation forKey:nil];
}

代碼效果 :

Jietu20220722-143502-HD.gif

CABasicAnimation -- 基本的單一關(guān)鍵幀動(dòng)畫

繼承自CAPropertyAnimation,為圖層(CALayer)的屬性提供基本的單一關(guān)鍵幀動(dòng)畫功能的對(duì)象侨歉。使用繼承的animationWithKeyPath:方法創(chuàng)建CABasicAnimation的實(shí)例屋摇,并在關(guān)鍵路徑(KeyPath)中指定要在渲染樹中添加動(dòng)畫的屬性的。例如:[CABasicAnimation animationWithKeyPath:@"transform.rotation"]描述了了一個(gè)旋轉(zhuǎn)動(dòng)畫幽邓。

以下是定義在其間插值的屬性值的對(duì)象炮温,所有選項(xiàng)都是可選的,而且非nil的屬性不應(yīng)該超過兩個(gè)牵舵,對(duì)象類型應(yīng)該與被動(dòng)畫的屬性類型相匹配(使用CALayer.h中描述的標(biāo)準(zhǔn)規(guī)則)柒啤。支持的動(dòng)畫模式有:

“fromValue”和“toValue”都不為nil,在fromValue和toValue之間進(jìn)行插值畸颅。

“fromValue”和“byValue”不為nil担巩,在“fromValue”和“fromValue”加上“byValue”之間進(jìn)行插值。

“byValue”和“toValue”不為nil没炒,在“toValue”減去“byValue”和“toValue”之間進(jìn)行插值涛癌。

“fromValue”非nil,在“fromValue”和屬性的當(dāng)前表示值之間進(jìn)行插值送火。

“toValue”非nil拳话,在渲染樹中圖層的當(dāng)前屬性值和“toValue”之間進(jìn)行插值。

“byValue”非nil种吸,在渲染樹中圖層的當(dāng)前屬性值和加上“byValue”的值之間進(jìn)行插值弃衍。

CABasicAnimation的屬性
@property(nullable, strong) id fromValue;

屬性描述 : 定義調(diào)用方用于開始插值的值

@property(nullable, strong) id toValue;

屬性描述 : 定義調(diào)用方用于結(jié)束插值的值骨稿。

@property(nullable, strong) id byValue;

屬性描述 : 定義調(diào)用方用于執(zhí)行相對(duì)插值的值笨鸡。

\color{red}{CABasicAnimation簡(jiǎn)單的代碼示例:}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 設(shè)置視圖
    UIView *view = [[UIView alloc]initWithFrame:CGRectZero];
    view.backgroundColor = [UIColor redColor];
    [self.view addSubview:view];
    view.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [view.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [view.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
        [view.widthAnchor constraintEqualToConstant:100],
        [view.heightAnchor constraintEqualToConstant:100],
    ]];
    // 設(shè)置動(dòng)畫為旋轉(zhuǎn)
    CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    // 動(dòng)畫持續(xù)時(shí)間
    animation.duration = 5.0f;
    // 重復(fù)次數(shù)(HUGE_VALF為無(wú)限重復(fù))
    animation.repeatCount = HUGE_VALF;
    // 開始時(shí)的位置
    animation.fromValue = [NSNumber numberWithFloat:0];
    // 結(jié)束時(shí)的位置
    animation.toValue = [NSNumber numberWithFloat:M_PI * 2];
    // 添加動(dòng)畫
    [view .layer addAnimation:animation forKey:nil];
}

簡(jiǎn)單的旋轉(zhuǎn):

Jietu20220722-163511-HD.gif

對(duì)keypath提供的簡(jiǎn)單動(dòng)畫的效果的匯總

//CATransform3D Key Paths
static NSString *kCARotation = @"transform.rotation";            //旋轉(zhuǎn)
static NSString *kCARotationX = @"transform.rotation.x";         //圍繞X軸旋轉(zhuǎn)
static NSString *kCARotationY = @"transform.rotation.y";         //圍繞Y軸旋轉(zhuǎn)
static NSString *kCARotationZ = @"transform.rotation.z";         //圍繞Z軸旋轉(zhuǎn)
//縮放
static NSString *kCAScale = @"transform.scale";                  //縮放
static NSString *kCAScaleX = @"transform.scale.x";               //對(duì)X方向進(jìn)行縮放
static NSString *kCAScaleY = @"transform.scale.y";               //對(duì)Y方向進(jìn)行縮放
static NSString *kCAScaleZ = @"transform.scale.z";               //對(duì)Z方向進(jìn)行縮放
//平移
static NSString *kCATranslation = @"transform.translation";      //平移
static NSString *kCATranslationX = @"transform.translation.x";   //對(duì)X方向進(jìn)行平移
static NSString *kCATranslationY = @"transform.translation.y";   //對(duì)Y方向進(jìn)行平移
static NSString *kCATranslationZ = @"transform.translation.z";   //對(duì)Z方向進(jìn)行平移
//平面
static NSString *kCAPosition = @"position";                      //CGPoint中心點(diǎn)改變位置
static NSString *kCAPositionX = @"position.x";                   //CGPoint中心點(diǎn)X方向改變位置
static NSString *kCAPositionY = @"position.y";                   //CGPoint中心點(diǎn)Y方向改變位置
//CGRect
static NSString *kCABoundsSize = @"bounds.size";                 //自身界限的大小
static NSString *kCABoundsSizeW = @"bounds.size.width";          //自身界限的寬度
static NSString *kCABoundsSizeH = @"bounds.size.height";         //自身界限的高度
static NSString *kCABoundsOriginX = @"bounds.origin.x";          //自身界限的起點(diǎn)X方向
static NSString *kCABoundsOriginY = @"bounds.origin.y";          //自身界限的起點(diǎn)Y方向
//Layer
static NSString *kCAOpacity = @"opacity";                        //透明度
static NSString *kCABackgroundColor = @"backgroundColor";        //背景色
static NSString *kCACornerRadius = @"cornerRadius";              //圓角
static NSString *kCABorderWidth = @"borderWidth";                //邊框
static NSString *kCAShadowColor = @"shadowColor";                //陰影顏色
static NSString *kCAShadowOffset = @"shadowOffset";              //偏移量CGSize
static NSString *kCAShadowOpacity = @"shadowOpacity";            //陰影透明度
static NSString *kCAShadowRadius = @"shadowRadius";              //陰影圓角

CASpringAnimation - 彈簧力動(dòng)畫

CASpringAnimation繼承自CABasicAnimation,對(duì)層的屬性應(yīng)用類似彈簧力的動(dòng)畫坦冠。通常使用彈簧動(dòng)畫設(shè)置層位置的動(dòng)畫形耗,使其看起來被彈簧拉向目標(biāo)。層離目標(biāo)越遠(yuǎn)辙浑,對(duì)它的加速度就越大激涤。CASpringAnimation允許控制基于物理的屬性,例如彈簧的阻尼和剛度判呕。

CASpringAnimation提供的屬性
@property CGFloat mass;

屬性描述 : 附著在彈簧末端的物體的質(zhì)量倦踢,默認(rèn)質(zhì)量為1。增加該值將增加彈簧彈力效果侠草,附加與彈簧動(dòng)畫的對(duì)象將受到更多的振蕩次數(shù)和更大的彈力回調(diào)辱挥,從而增加動(dòng)畫沉降過程持續(xù)時(shí)間;減小該值將減少?gòu)椈闪πЧ咛椋袷幋螖?shù)與彈力回調(diào)減少晤碘,從而減少動(dòng)畫沉降過程持續(xù)時(shí)間褂微。

@property CGFloat stiffness;

屬性描述彈簧動(dòng)畫彈簧的剛度系數(shù),默認(rèn)的剛度系數(shù)為100园爷。增加剛度可增加振蕩次數(shù)宠蚂,并增加動(dòng)畫沉降過程持續(xù)時(shí)間;減小剛度會(huì)減少振蕩次數(shù)童社,并減少動(dòng)畫沉降過程持續(xù)時(shí)間求厕。

@property CGFloat damping;

屬性描述抑制彈簧彈力的阻尼值,默認(rèn)值是10扰楼。減少這個(gè)值可以減少每次振蕩的能量損失呀癣,動(dòng)畫值將超過toValue,并且使動(dòng)畫沉降過程持續(xù)時(shí)間大于動(dòng)畫持續(xù)時(shí)間灭抑。增加數(shù)值會(huì)增加能量損耗十艾,振蕩會(huì)越來越少,越來越小腾节,動(dòng)畫沉降過程持續(xù)時(shí)間可能會(huì)小于動(dòng)畫持續(xù)時(shí)間忘嫉。

@property CGFloat initialVelocity;

屬性描述附著在彈簧上的物體的初始速度,默認(rèn)為0案腺,表示不移動(dòng)的對(duì)象庆冕。負(fù)值表示附著在彈簧上對(duì)象先反向遠(yuǎn)離彈簧連接點(diǎn),正值表示附著在彈簧上對(duì)象加速在彈簧附著點(diǎn)正向移動(dòng)劈榨。

@property(readonly) CFTimeInterval settlingDuration;

屬性描述彈簧系統(tǒng)返回到靜止時(shí)要考慮的所需的估計(jì)持續(xù)時(shí)間访递,將為當(dāng)前動(dòng)畫參數(shù)計(jì)算持續(xù)時(shí)間。

\color{red}{一個(gè)簡(jiǎn)單的掉落效果代碼示例:}

@interface TSChannelFiveViewController ()<CAAnimationDelegate>

@property (nonatomic, strong) UIView *myView;
@property (nonatomic, strong) NSLayoutConstraint *myViewYConstraint;

@end

@implementation TSChannelFiveViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //設(shè)置按鈕
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.backgroundColor = [UIColor blueColor];
    [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [button.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [button.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
    ]];
    // 設(shè)置視圖
    self.myView = [[UIView alloc]initWithFrame:CGRectZero];
    self.myView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.myView];
    UITapGestureRecognizer *singleClick = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(singleClickEvent)];
    [self.myView addGestureRecognizer:singleClick];
    self.myView.translatesAutoresizingMaskIntoConstraints = NO;
    self.myViewYConstraint = [self.myView.bottomAnchor constraintEqualToAnchor:self.view.topAnchor];
    [NSLayoutConstraint activateConstraints:@[
        [self.myView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        self.myViewYConstraint,
        [self.myView.widthAnchor constraintEqualToConstant:100],
        [self.myView.heightAnchor constraintEqualToConstant:100],
    ]];
    
}

/// 按鈕點(diǎn)擊事件
- (void)buttonClick:(UIButton *)button {
    // 設(shè)置動(dòng)畫為旋轉(zhuǎn)
    CASpringAnimation * animation = [CASpringAnimation animationWithKeyPath:@"position.y"];
    animation.delegate = self;
    // 動(dòng)畫持續(xù)時(shí)間
    animation.duration = 2.0f;
    // 結(jié)束時(shí)的位置
    animation.toValue = @(CGRectGetMidY(self.view.frame));
    // 附著在彈簧上的物體質(zhì)量
    animation.mass = 3;
    // 彈簧剛度
    animation.stiffness = 300;
    // 彈簧彈力的阻尼
    animation.damping = 9;
    // 使視圖停留在動(dòng)畫結(jié)束的位置
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = NO;
    // 添加動(dòng)畫
    [self.myView.layer addAnimation:animation forKey:nil];
}

/// 視圖點(diǎn)擊事件
- (void)singleClickEvent {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"點(diǎn)擊了" message:nil preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        [alert dismissViewControllerAnimated:YES completion:nil];
    }];
    [alert addAction:cancelAction];
    [self presentViewController:alert animated:YES completion:nil];
}

#pragma mark - CAAnimationDelegate

/// 動(dòng)畫結(jié)束
/// @param anim 結(jié)束的動(dòng)畫對(duì)象
/// @param flag 指示動(dòng)畫是否因?yàn)檫_(dá)到其活動(dòng)持續(xù)時(shí)間后而結(jié)束的標(biāo)志
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    if (flag) {
        self.myViewYConstraint.active = NO;
        self.myViewYConstraint = [self.myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor];
        self.myViewYConstraint.active = YES;
    }
}

@end

在動(dòng)畫結(jié)束后更新了一下約束同辣,因?yàn)閷釉趧?dòng)畫完成后拷姿,雖然視圖保留了動(dòng)畫完成時(shí)的位置,但視圖的frame實(shí)際是沒有改變的旱函,如果沒有更新約束响巢,視圖是不響應(yīng)點(diǎn)擊事件的,因?yàn)楦緵]有點(diǎn)擊到視圖上棒妨。效果如圖:

Jietu20220726-170811-HD.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末踪古,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子券腔,更是在濱河造成了極大的恐慌伏穆,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纷纫,死亡現(xiàn)場(chǎng)離奇詭異枕扫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)辱魁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門铡原,熙熙樓的掌柜王于貴愁眉苦臉地迎上來偷厦,“玉大人商叹,你說我怎么就攤上這事燕刻。” “怎么了剖笙?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵卵洗,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我弥咪,道長(zhǎng)过蹂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任聚至,我火速辦了婚禮酷勺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扳躬。我一直安慰自己脆诉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布贷币。 她就那樣靜靜地躺著击胜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪役纹。 梳的紋絲不亂的頭發(fā)上偶摔,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音促脉,去河邊找鬼辰斋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛瘸味,可吹牛的內(nèi)容都是我干的宫仗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼硫戈,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼锰什!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起丁逝,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤汁胆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后霜幼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嫩码,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年罪既,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铸题。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铡恕。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丢间,靈堂內(nèi)的尸體忽然破棺而出探熔,到底是詐尸還是另有隱情,我是刑警寧澤烘挫,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布诀艰,位于F島的核電站,受9級(jí)特大地震影響饮六,放射性物質(zhì)發(fā)生泄漏其垄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一卤橄、第九天 我趴在偏房一處隱蔽的房頂上張望绿满。 院中可真熱鬧,春花似錦窟扑、人聲如沸喇颁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)无牵。三九已至,卻和暖如春厂抖,著一層夾襖步出監(jiān)牢的瞬間茎毁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工忱辅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留七蜘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓墙懂,卻偏偏與公主長(zhǎng)得像橡卤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子损搬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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