IOS--CALayer(圖層類)

##一、CALayer概述git

CALayer類在概念上和UIView相似,一樣也是一些被層級關係 樹管理的矩形塊,一樣也能夠包含一些內容(像圖片,文本或者背景色),管理子圖層的位置。它們有一些⽅法和屬性用來作動畫和變換。 CALayer是CoreAnimation部分的內容,CALayer的概念相似於photoshop中層的概念,每一個UIView都有一個根CALayer,每一個CALayer又能夠添加子CALayer,從結構上來看CALayer是一種樹形結構,UIView的繪製工做都交由CALayer完成。github

和UIView最大的不一樣是CALayer不處理⽤用戶的交互。由於CALayer並不清楚具體的響應鏈(iOS經過視圖層級關係用來傳送觸摸事件的機制),因而它並不可以響應事件,即便它提供了一些方法來判斷是否一個觸點在圖層的範圍以內。數據結構

##二、平行的層級關係 每個UIview都有一個CALayer實例的圖層屬性,也就是所謂的backing layer,視圖的職責就是建立並管理這個圖層,以確保當子視圖在層級關係中添加或者被移除的時候,他們關聯的圖層也一樣對應在層級關係樹當中有相同的操做。 實際上,這些背後關聯的圖層纔是真正用來在屏幕上顯示和作畫,UIView僅僅是對CALayer的一個封裝,而後提供了處理觸摸的具體功能,以及CoreAnimation高級接口。可是爲何iOS要基於UIView和CALayer提供兩個平行的層級關係呢?爲何不⽤一個簡單的層級來處理全部事情呢?緣由在於要作職責分離,這樣也能避免不少重複代碼。在iOS和Mac OS兩個平臺上,事件和⽤戶交互有不少地方的不一樣,基於多點觸控的用戶界⾯和基於⿏標鍵盤有着本質的區別,這就是爲何iOS有UIKit和UIView,可是Mac OS有AppKit和NSView的緣由。他們功能上很類似,可是在實現上有着顯著的區別。ide

實際上,這裏並非兩個層級關係,而是四個,每個都扮演不一樣的角色,除了視圖層級和圖層樹以外,還存在呈現樹和渲染樹.函數

  • 呈現樹:呈現樹包含了當前動畫發生時候將要顯示的值,例如你要給圖層背景顏色設置新的值的時候,它會當即修改圖層樹裏面相應的值。可是在呈現樹裏面背景顏色值在將要顯示給用戶的時候才被更新爲新值。oop

  • 渲染樹:渲染樹是私有的,你沒法訪問到,渲染樹在渲染圖層的時候使用呈現樹的值,爲了避免阻塞主線程,渲染的過程是在單獨的進程或線程中進行的,因此你會發現Animation的動畫並不會阻塞主線程。學習

前⾯面已經講過,UIView是對CALayer的封裝,那爲何咱們還要學習CALayer呢?由於UIView封裝的 API在有些狀況下並不能知足咱們的需求,好比:字體

1.陰影,圓⾓角,邊框       
2.3D變換    
3.⾮矩形範圍    
4.遮罩    
5.⾮線性動畫

##三、CALayer經常使用屬性 咱們能夠進入CALayer.h中查看CALayer支持的屬性,其中註解中標註Animation的屬性表示支持隱式動畫,當這些屬性的值改變時系統自帶了平滑過渡的動畫效果(非根Layer支持)動畫

下表列出了CALayer經常使用的屬性:線程

屬性 說明 是否支持隱式動畫
anchorPoint 和中心點position重合的一個點,稱爲「錨點」,錨點的描述是相對於x、y位置比例而言的默認在圖像中心點(0.5,0.5)的位置
backgroundColor 圖層背景顏色
borderColor 邊框顏色
borderWidth 邊框寬度
bounds 圖層大小
contents 圖層顯示內容,例如能夠將圖片做爲圖層內容顯示
contentsRect 圖層顯示內容,例如能夠將圖片做爲圖層內容顯示
contentsRect 圖層顯示內容的大小和位置
cornerRadius 圓角半徑
doubleSided 圖層背面是否顯示,默認爲YES
frame 圖層大小和位置,不支持隱式動畫,因此CALayer中不多使用frame,一般使用bounds和position代替
zPosition 圖層的重疊順序
hidden 是否隱藏
mask 圖層蒙版
maskToBounds 是否剪切超出父圖層邊界的部分,默認爲NO
opacity 透明度 ,相似於UIView的alpha
position 圖層中心點位置,相似於UIView的center
shadowColor 陰影顏色
shadowOffset 陰影偏移量
shadowOpacity 陰影透明度,注意默認爲0,若是設置陰影必須設置此屬性
shadowPath 陰影的形狀
shadowRadius 陰影模糊半徑
sublayers 設置多個子圖層
sublayerTransform 子圖層形變
transform 圖層形變
  • 隱式屬性動畫的本質是這些屬性的變更默認隱含了CABasicAnimation動畫實現,詳情你們能夠參照Xcode幫助文檔中「Animatable Properties」一節。
  • 在CALayer中不多使用frame屬性,由於frame自己不支持動畫效果,一般使用bounds和position代替。
  • CALayer中透明度使用opacity表示而不是alpha;中心點使用position表示而不是center。
  • anchorPoint屬性是圖層的錨點,範圍在(0~1,0~1)表示在x、y軸的比例,這個點永遠能夠同position(中心點)重合,當圖層中心點固定後,調整anchorPoint便可達到調整圖層顯示位置的做用(由於它永遠和position重合)

建立layer並添加到根layer上:

CALayer *layer = [[CALayer alloc] init];
    layer.frame = CGRectMake(10, 320, 330, 200);
    layer.backgroundColor = [UIColor blueColor].CGColor;
    
    // 將圖層添加到父圖層
    [self.view.layer addSublayer:layer];

填充圖片內容,須要將 UIImage 橋接(__bridge)到CGImage:

layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"image4.jpg"].CGImage);

使用layer CATextLayer 子類填充文字:

CATextLayer *textLayer = [[CATextLayer alloc] init];
    textLayer.frame = CGRectMake(10, 550, 300, 30);
    textLayer.string = @"這是layer填充的文字內容";
    //字體顏色
    textLayer.foregroundColor = [UIColor blackColor].CGColor;
    textLayer.backgroundColor = [UIColor redColor].CGColor;
    textLayer.font = (__bridge CFTypeRef _Nullable)([UIFont systemFontOfSize:20 weight:500]);
    textLayer.fontSize = 20;
    textLayer.alignmentMode = @"center";
    // textLayer.truncationMode = @"middle";
    
    [self.view.layer addSublayer:textLayer];

##四、CALayer圖層繪製

  • 經過直接設置CALayer的contents屬性進行圖層繪製
CALayer *layer = [CALayer layer];
    // layer.frame = CGRectMake(0, 100, 350, 200);
    layer.backgroundColor = [UIColor orangeColor].CGColor;
    
    // 一、bounds: 尺寸
    layer.bounds = CGRectMake(0, 0, 220, 220);
    // 二、position: 定位點
    layer.position = self.view.center;
    
    // 三、錨點、支點:決定layer上的哪一個點在 position 點上,默認(0.5, 0.5),範圍:(0,0) ~ (1,1)
    layer.anchorPoint = CGPointMake(0.5, 0.5);
    
    // 四、z方向的層級
    layer.zPosition = 2;
    
    // 五、設置圓角:爲直徑的一半時會成圓形
    layer.cornerRadius = 110;
    
    // 六、填充內容
    layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"image1.jpg"].CGImage);
    //設置背景顏色
    layer.backgroundColor = [UIColor orangeColor].CGColor;
    // 七、是否能夠裁剪多餘的圖層
    layer.masksToBounds = YES;
    
    // 八、設置邊框寬度和顏色
    //layer.borderWidth = 5;
    //layer.borderColor = [UIColor lightGrayColor].CGColor;
    
    [self.view.layer addSublayer:layer];
    
}

實現效果:

須要注意的是上面代碼中繪製圖片圓形裁切效果時若是不設置masksToBounds是沒法顯示圓形,可是對於其餘圖形卻沒有這個限制。緣由就是當繪製一張圖片到圖層上的時候會從新建立一個圖層添加到當前圖層,這樣一來若是設置了圓角以後雖然底圖層有圓角效果,可是子圖層仍是矩形,只有設置了masksToBounds爲YES讓子圖層按底圖層剪切才能顯示圓角效果。

  • 擴展--帶陰影效果的圓形圖片裁切

若是設置了masksToBounds=YES以後確實能夠顯示圖片圓角效果,但遺憾的是設置了這個屬性以後就沒法設置陰影效果。由於masksToBounds=YES就意味着外邊框不能顯示,而陰影偏偏做爲外邊框繪製的,這樣兩個設置就產生了矛盾。要解決這個問題不妨換個思路:使用兩個大小同樣的圖層,下面的圖層負責繪製陰影,上面的圖層用來顯示圖片。

//陰影圖層
    CALayer *layerShadow = [[CALayer alloc]init];
    layerShadow.bounds = CGRectMake(0, 0, 220, 220);
    layerShadow.position= self.view.center;
    layerShadow.cornerRadius = 110;
    //陰影顏色
    layerShadow.shadowColor = [UIColor grayColor].CGColor;
    //陰影偏移量
    layerShadow.shadowOffset = CGSizeMake(5, 1);
    //陰影透明度
    layerShadow.shadowOpacity = 1;
    layerShadow.borderColor = [UIColor whiteColor].CGColor;
    layerShadow.borderWidth = 5;
    
    [self.view.layer addSublayer:layerShadow];
}

實現效果:

##五、CALayer3D變換

  • 隱式動畫: 當layer的屬性發生變換時會默認產生動畫效果,動畫時間0.25s
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    UITouch *touch=[touches anyObject];
    CGFloat width=layer.bounds.size.width;
    
    if (width==Width) {
        width=Width*2;
        // 組合 CATransform3D
        CATransform3D transform_01 = CATransform3DScale(layer.transform, 1, 1, 1);
        CATransform3D transform_02 = CATransform3DRotate(layer.transform, M_PI/6, 0, 0, 1);
        layer.transform = CATransform3DConcat(transform_01, transform_02);
        layer.cornerRadius = width/2;
        layer.backgroundColor = [UIColor blueColor].CGColor;
    }else{
        width=Width;
        layer.cornerRadius = 0;
        layer.backgroundColor = [UIColor orangeColor].CGColor;
    }
    layer.bounds=CGRectMake(0, 0, width, width);
    layer.position=[touch locationInView:self.view];
    
}
@end

實現效果:

  • CATransform3D數據結構定義了一個三維變換(4x4 CGFloat值的矩陣),用於圖層的旋轉,縮放,偏移,歪斜和應用的透視,經常使用函數有下面幾種:

1:CATransform3DMakeRotation(CGFloat angle, <#CGFloat x#>, <#CGFloat y#>, <#CGFloat z#>)

若是x=1,y=0,z=0則繞x軸旋轉angle角度

若是x=0,y=1,z=0則繞y軸旋轉angle角度

若是x=0,y=0,z=1則繞z軸旋轉angle角度

若是x=1,y=1,z=0則繞x軸和y軸夾角旋轉angle角度

若是x=1,y=1,z=1則繞3軸夾角旋轉angle角度

上訴的旋轉中心都是layer的錨點(anchorPoint)

2:CATransform3DRotate(<#CATransform3D t#>, <#CGFloat angle#>, <#CGFloat x#>, <#CGFloat y#>, <#CGFloat z#>)  功能與上一函數相似,但能夠疊加一個CATransform3D效果

3:CATransform3DMakeScale(<#CGFloat sx#>, <#CGFloat sy#>, <#CGFloat sz#>) 用於縮放,三個參數是x軸,Y軸,z軸上的縮放程度,縮放中心是layer的錨點

4:CATransform3DScale(<#CATransform3D t#>, <#CGFloat sx#>, <#CGFloat sy#>, <#CGFloat sz#>)   功能與上一函數相似,但能夠疊加一個CATransform3D效果

5:CATransform3DMakeTranslation(CGFloat tx, <#CGFloat ty#>, <#CGFloat tz#>)  用於平移

6:CATransform3DTranslate(<#CATransform3D t#>, <#CGFloat tx#>, <#CGFloat ty#>, <#CGFloat tz#>) 用於移動

7:CATransform3DConcat(CATransform3D a, <#CATransform3D b#>) 將兩個CATransform3D效果疊加起來

咱們也能夠經過KVC更方便的設置transform的屬性

[layer setValue:@M_PI forKeyPath:@"transform.rotation.x"];

能夠經過KVC設置如下與transform相關的屬性

transform.rotation.x

``transform.rotation.y`

transform.rotation.z

transform.scale.x

transform.scale.y

transform.scale.z

transform.translation.x

transform.translation.y

transform.translation.z

##六、CALayer事務 CALayer中"Animatable"屬性變化都在CATrasaction的管理內,以前提到的屬性支持隱式動畫是指在某次Runroop中修改"Animatable"時,若是沒有設置事務,則會自動建立一個CATransaction,並在當前線程的下一個RunLoop中commit這個CATransaction。

事務能夠被嵌套,容許你禁用部分動畫的行爲或者在屬性被修改的時候產生 的動畫使用不一樣的時間。僅當最外層的事務被提交的時候,動畫纔會發生。

事務開啓:[CATransaction begin]
禁止動畫效果:[CATransaction setDisableActions:YES];
事務提交:[CATransaction commit]

咱們能夠經過事務控制動畫的時長,甚至禁止動畫效果,還能夠設置completionBlock,噹噹前CATransaction的全部動畫執行結束後,,completionBlock會被調用

##Demo下載地址: https://github.com/fuxinto/HfxDemo

相關文章
相關標籤/搜索