核心動畫 Core Animation(一胖替、Layer基礎)

核心動畫(Core Animation)是iOS和OS X上圖形渲染和動畫的基礎設施焊唬,用于為應用程序的視圖和其他視覺元素設置動畫故痊。核心動畫本身不是繪圖系統(tǒng)顶瞳。它是用于在硬件中合成和操縱應用程序內(nèi)容的基礎設施。這種基礎設施的核心是層(layer)對象慨菱,用于管理和操縱您的內(nèi)容甜孤。一個圖層將您的內(nèi)容捕獲到位圖中,這些位圖可以通過圖形硬件輕松操作。在大多數(shù)應用程序中,圖層用作管理視圖內(nèi)容的一種方式,但也可以根據(jù)需要創(chuàng)建獨立圖層烤黍。
?基于layer層的繪圖與傳統(tǒng)的基于視圖的繪圖技術(shù)有很大的不同规哲。使用基于視圖的繪圖,對視圖本身的更改通常會導致調(diào)用視圖的drawRect:方法以使用新參數(shù)重新繪制內(nèi)容。但是以這種方式繪制是昂貴的吕粹,因為它是使用主線程上的CPU完成的。Core Animation可以通過在硬件中操作緩存的位圖來實現(xiàn)相同或相似的效果,從而避免這種代價母市。

一浑槽、關于Layer的幾個重要屬性及方法

CALayer類中屬性和方法有很多,大多數(shù)和使用View的方式相同,在此不多贅述煮落,具體可以自行查看CALayer.h文件敞峭。下面主要介紹一下比較重要的屬性方法。

1蝉仇、屬性:
  • position(CGPoint):位置旋讹,與view中的center差不多,默認情況是layer的中心轿衔。但是會受錨點(anchorPoint)影響而改變沉迹。
  • zPosition(CGFloat):layer的position在父類(super layer)上的Z軸分量,默認為零害驹。
  • anchorPoint(CGPoint):錨點鞭呕,使用的是以自身為參考的單位坐標系,默認為(0.5裙秋, 0.5)琅拌。當操縱層的屬性position或transform屬性時缨伊,錨點的影響最為明顯摘刑。position屬性總是相對于圖層的錨點指定,并且對于應用于圖層的任何轉(zhuǎn)換也會相對于錨點發(fā)生刻坊。
圖例
  • anchorPointZ(CGFloat):layer的anchorPoint在Z軸上的分量枷恕,默認為零。

  • transform(CATransform3D):作用于layer的3D變換谭胚。默認是單位矩陣CATransform3DIdentity徐块。

    • 每個layer都有兩個變換矩陣屬性(transform、sublayerTransform)灾而,可以使用它們來操縱圖層及其內(nèi)容胡控。CALayer的transform屬性指定要既適用于層和其嵌入式子層的變換。通常旁趟,當要修改圖層本身時昼激,可以使用此屬性。sublayerTransform屬性定義了僅適用于子層的附加變換锡搜,最常用于向場景內(nèi)容添加透視視覺效果橙困。
    • 因為Core Animation值可以在三維中指定,所以每個坐標點有四個值必須乘以四乘四個矩陣(見下圖)耕餐。核心動畫提供了一套全面的功能凡傅,用于創(chuàng)建縮放,轉(zhuǎn)換和旋轉(zhuǎn)矩陣以及進行矩陣比較(具體可見CATransform3D.h文件肠缔,里面方法的使用可以參考CATransform3D -> 3D變換
      )夏跷。除了使用函數(shù)操縱變換之外哼转,Core Animation擴展了鍵值編碼支持,允許使用關鍵路徑修改變換槽华。
  • sublayerTransform(CATransform3D):當將內(nèi)容呈現(xiàn)到接收器的輸出中時释簿,將3D變換應用于“sublayers”數(shù)組的每個成員。 通常用作投影矩陣以將透視和其他觀看效果添加到模型硼莽。默認是單位矩陣庶溶。

  • sublayers(NSArray<CALayer >):子layer的集合。

  • masksToBounds(BOOL):是否沿著邊界裁剪懂鸵。

  • contents(id):layer的內(nèi)容由包含要顯示的視覺數(shù)據(jù)的位圖組成偏螺。您可以通過以下三種方式之一提供該位圖的內(nèi)容:

    • 直接將圖像對象直接分配給圖層對象的contents屬性。(這種技術(shù)最適合從未或很少改變的圖層內(nèi)容匆光。注意必須為CGImageRef類型)
    • 將一個委托對象分配給圖層套像,讓代理繪制圖層的內(nèi)容。(此技術(shù)最適合可能會周期性更改并可由外部對象(如視圖)提供的圖層內(nèi)容终息。)
    • 定義一個layer的子類并覆蓋其繪圖方法夺巩,自己提供圖層內(nèi)容。(如果您要創(chuàng)建自定義層子類周崭,或者如果要更改圖層的基本繪圖行為柳譬,則此技術(shù)是適用的。)
  • contentsRect(CGRect):默認是{0续镇, 0美澳, 1,1}通俗來說就是將layer看成單位矩形摸航,取其中的一部分制跟。所有參數(shù)一般是[0-1]。

  • contentsGravity(NSString):決定分配給contents屬性圖像一什么方式呈現(xiàn)酱虎,一般分配給該屬性的值分為兩類:

    • 基于位置的重力常數(shù)允許將圖像定向到圖層邊界矩形的特定邊緣或角落雨膨,而 不縮放圖像。具體見 PS-1读串。
    • 基于縮放的重力常數(shù)允許來拉伸圖像聊记。具體見 PS-2
  • contentsScale(CGFloat):默認值是1.0爹土,屬性主要作用是適應Retina屏與非Retina屏的甥雕,如果是Retina屏則設置為2.0。一般可以這樣設置[UIScreen mainScreen].scale胀茵。

  • contentsCenter(CGFloat):默認是{0社露, 0, 1琼娘,1}峭弟,在contentsRect的基礎上確定縮放比例附鸽,主要決定因子是前兩個元素,決定了原圖縱橫/現(xiàn)圖縱橫的比例瞒瘸,如:0.2則原圖被放大五倍?辣浮!情臭!

  • opaque(BOOL):由-drawInContext提供的圖層內(nèi)容是完全不透明的省撑。 默認為NO。

  • opacity(float):layer的透明度俯在,默認是1竟秫。

還有一些常見的屬性:如frame, hidden, backgroundColor, cornerRadius, borderWidth, borderColor, shadowColor,shadowOpacity, shadowOffset, shadowRadius, shadowPath 等。

除此之外跷乐,核心動畫對它所屬的CAAnimation和CALayer類擴展了NSKeyValueCoding的協(xié)議 --- 必須使用setValue:forKeyPath:valueForKeyPath:方法來設置和獲取這些字段肥败,并增加了關鍵路徑對CGPointCGRect愕提,CGSize馒稍,和CATransform3D類型的支持(表-1)。所以可以直接使用KVC對其 屬性 進行賦取值浅侨,在這里需要特別注意對transform等結(jié)構(gòu)體來使用keyPath的情形(表-2)

表-1

C類 包裝類
CGPoint /CGSize/CGRect/CATransform3D NSValue

表-2

字段路徑 包裝類及描述
transform.translation NSValue(包含CGSize數(shù)據(jù)類型) , 在x和y軸上平移的量
transform. translation.x NSNunber , 沿x軸平移
transform. translation.y NSNunber , 沿y軸平移
transform. translation.z NSNunber , 沿z軸平移
transform. scale NSNunber , xyz三個比例因子的平均值
transform. scale.x NSNunber , 沿x軸縮放
transform. scale.y NSNunber , 沿y軸縮放
transform. scale.z NSNunber , 沿z軸縮放
transform. rotation NSNunber , 沿z軸旋轉(zhuǎn)的弧度纽谒,與transform. rotation.z相同
transform. rotation.x NSNunber , 沿x軸旋轉(zhuǎn)的弧度
transform. rotation.y NSNunber , 沿y軸旋轉(zhuǎn)的弧度
transform. rotation.z NSNunber , 沿z軸旋轉(zhuǎn)的弧度
*** ***
position NSValue
position.x NSNunber
position.y NSNunber
*** ***
bounds/frame NSValue
bounds.origin 同position
bounds. size NSValue
bounds. size.width NSNumber
bounds. size.height NSNumber

PS-1:基于位置的重力常數(shù):

CA_EXTERN NSString * const kCAGravityCenter
CA_EXTERN NSString * const kCAGravityTop
CA_EXTERN NSString * const kCAGravityBottom
CA_EXTERN NSString * const kCAGravityLeft
CA_EXTERN NSString * const kCAGravityRight
CA_EXTERN NSString * const kCAGravityTopLeft
CA_EXTERN NSString * const kCAGravityTopRight
CA_EXTERN NSString * const kCAGravityBottomLeft
CA_EXTERN NSString * const kCAGravityBottomRight
PS-1

PS-2:基于縮放的重力常數(shù):

CA_EXTERN NSString * const kCAGravityResize
CA_EXTERN NSString * const kCAGravityResizeAspect
CA_EXTERN NSString * const kCAGravityResizeAspectFill
PS-2
2、方法:
  • + (nullable id)defaultValueForKey:(NSString *)key;:在使用KVC時為鍵提供默認值仗颈。一般進行復寫來覆蓋原有方法進行默認值設置佛舱。

  • - (void)display;:重新加載圖層的內(nèi)容。 用法:如果實現(xiàn)了委托方法挨决,默認會調(diào)用displayLayer:委托方法。否則订歪,display方法會調(diào)用drawInContext方法脖祈,然后更新圖層的“contents”屬性。但是一般不主動調(diào)用刷晋!

  • - (void)setNeedsDisplay;盖高、- (void)setNeedsDisplayInRect:(CGRect)r;:與上面的方法差不多,但是可以主動調(diào)用眼虱。如果設置了rect喻奥,則只有該層的該區(qū)域無效。

  • - (void)displayIfNeeded;:繪圖系統(tǒng)在需要時自動調(diào)用捏悬,如果已經(jīng)調(diào)用了setNeedsDisplay撞蚕,該方法無效。

  • - (void)drawInContext:(CGContextRef)ctx;默認的display方法會創(chuàng)建一個視圖圖形上下文并將其傳遞給drawInContext:方法,與[UIView drawRect:]方法相似过牙。


代理方法:

  • - (void)displayLayer:(CALayer *)layer;如果實現(xiàn)了代理同時定義了此方法則甥厦,-display方法會調(diào)用此方法纺铭,該實現(xiàn)負責創(chuàng)建位圖并將其分配給圖層的contents屬性。

  • - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)cox; -drawInContext調(diào)用此方法刀疙,創(chuàng)建一個圖形上下文來繪制該位圖舶赔,然后調(diào)用委托方法來填充位圖。如果-displayLayer: 方法存在谦秧,則該方法不調(diào)用竟纳,無效。

  • - (void)layerWillDraw:(CALayer *)layer:新加的方法疚鲤,如果定義蚁袭,則由-display方法的默認實現(xiàn)調(diào)用。 允許代理在-drawLayer之前配置影響內(nèi)容的任何圖層狀態(tài)石咬。同樣揩悄,如果-displayLayer: 方法存在,則該方法不調(diào)用鬼悠,無效删性。

所以綜以上方法總結(jié)layer方法響應鏈有兩種:

  • [layer setNeedDisplay] / [layer displayIfNeed] -> [layer display] -> [layerDelegate displayLayer:] 。
  • [layer setNeedDisplay] / [layer displayIfNeed] -> [layer display] -> [layer drawInContext:] -> [layerDelegate drawLayer: inContext:]焕窝。

關于動畫的方法:

  • (void)addAnimation:(CAAnimation *)anim forKey:(nullable NSString *)key;

  • (void)removeAllAnimations;

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

示例代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    _blueLayer = [CALayer layer];
    [_blueLayer setValue:(__bridge id)[UIColor blueColor].CGColor forKeyPath:@"backgroundColor"];
    [_blueLayer setValue:[NSValue valueWithCGPoint:CGPointZero] forKeyPath:@"anchorPoint"];
    [_blueLayer setValue:[NSValue valueWithCGRect:CGRectMake(0, 0, 1, 1)] forKeyPath:@"contentsRect"];
    [_blueLayer setValue:(__bridge id)[[UIImage imageNamed:@"boy"] CGImage] forKeyPath:@"contents"];
    [_blueLayer setValue:[NSValue valueWithCGRect:CGRectMake(50, 100, 200, 350)] forKeyPath:@"frame"];
    _blueLayer.delegate = self;
    [self.view.layer addSublayer:_blueLayer];
}
- (void)displayLayer:(CALayer *)layer
{
    if (once) {
        [_blueLayer setValue:[NSValue valueWithCGRect:CGRectMake(0, 0, 1, 0.7)] forKeyPath:@"contentsRect"];
        [_blueLayer setValue:(__bridge id)[[UIImage imageNamed:@"boy"] CGImage] forKeyPath:@"contents"];

    }else{
        [_blueLayer setValue:[NSValue valueWithCGRect:CGRectMake(0, 0, 1, 1)] forKeyPath:@"contentsRect"];
        [_blueLayer setValue:(__bridge id)[[UIImage imageNamed:@"girl"] CGImage] forKeyPath:@"contents"];
    }
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [_blueLayer setValue:kCAGravityResizeAspect forKeyPath:@"contentsGravity"];
    if (once) {
        once = NO;
        [UIView animateWithDuration:10.0 animations:^{
            [_blueLayer setValue:[NSNumber numberWithFloat:100] forKeyPath:@"transform.translation.x"];
            [_blueLayer setValue:[NSNumber numberWithFloat:100] forKeyPath:@"transform.translation.y"];
        }];
    }else{
        [UIView animateWithDuration:10.0 animations:^{
            [_blueLayer setValue:[NSValue valueWithCATransform3D:CATransform3DIdentity] forKeyPath:@"transform"];
        }];
        once = YES;
    }
    [_blueLayer setNeedsDisplay];
}
- (void)dealloc
{
    // 在這里代理一定要置空蹬挺!否則控制器無法釋放
    _blueLayer.delegate = nil;
}
效果圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市它掂,隨后出現(xiàn)的幾起案子巴帮,更是在濱河造成了極大的恐慌,老刑警劉巖虐秋,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榕茧,死亡現(xiàn)場離奇詭異,居然都是意外死亡客给,警方通過查閱死者的電腦和手機用押,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來靶剑,“玉大人蜻拨,你說我怎么就攤上這事∽” “怎么了缎讼?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坑匠。 經(jīng)常有香客問我血崭,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任功氨,我火速辦了婚禮序苏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捷凄。我一直安慰自己忱详,他們只是感情好,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布跺涤。 她就那樣靜靜地躺著匈睁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桶错。 梳的紋絲不亂的頭發(fā)上航唆,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機與錄音院刁,去河邊找鬼糯钙。 笑死,一個胖子當著我的面吹牛退腥,可吹牛的內(nèi)容都是我干的任岸。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼狡刘,長吁一口氣:“原來是場噩夢啊……” “哼享潜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嗅蔬,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤剑按,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后澜术,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艺蝴,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年瘪板,在試婚紗的時候發(fā)現(xiàn)自己被綠了吴趴。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡侮攀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出厢拭,到底是詐尸還是另有隱情兰英,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布供鸠,位于F島的核電站畦贸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜薄坏,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一趋厉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胶坠,春花似錦君账、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闻牡,卻和暖如春净赴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背罩润。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工玖翅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人割以。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓金度,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拳球。 傳聞我的和親對象是個殘疾皇子审姓,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

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