iOS核心動畫筆記6-專用圖層

專用圖層

1. CAShapeLayer

CAShapeLayer是一個經過矢量圖形而不是bitmap來繪製的圖層子類. 能夠指定繪製顏色, 線寬等屬性, 用CGPath來定義想要繪製的圖形, 最後CAShapeLayer就會自動渲染出來了. 相比使用 CoreAnimation直接在layer上繪製圖形, CAShapeLayer有如下優點:html

  1. 渲染快速. CAShapeLayer使用硬件加速, 繪製同一圖形會比用CoreGraphics快不少.
  2. 高效使用內存. 一個CAShapeLayer不須要像普通CALayer同樣建立一個寄宿圖形, 因此不管有多大, 都不會佔用太多的內存.
  3. 不會被圖形邊緣剪切掉. CAShapeLayer能夠在邊界以外繪製, 圖層路徑不會像使用CoreGraphics的普通CALayer同樣被剪裁掉.
  4. 不會出現像素化. 當給CAShapeLayer作3D變換時候, 它不會像一個有寄宿圖的普通圖層同樣變得像素畫.

1.1 建立一個CGPath

CAShapeLayer上繪製的形狀能夠經過CGPath來表示, CGPath對象能夠直接建立, 更好的是經過UIBezierPath建立CGPath(這種方法不須要手動釋放內存, 方便管理). 圖層路徑不必定是閉合的. 也能夠是開放的.ios

1.2 建立圓角

前面提到建立圓角視圖的方法, 就是CALayer提供的cornerRadius屬性, 可是經過CAShapeLayer能夠單獨制定每一個角是不是圓角.數組

測試代碼以下:app

// 測試使用CAShapeLayer繪製圓角
    TTShapeLayerView *shapeView = [[TTShapeLayerView alloc] initWithFrame:CGRectMake(10, 100, 100, 30)];
    [self.view addSubview:shapeView];
    
    
    
    UIRectCorner corners = UIRectCornerBottomRight | UIRectCornerTopLeft;
    CGSize radii = CGSizeMake(15, 15);
    
    UIBezierPath *bPath = [UIBezierPath bezierPathWithRoundedRect:shapeView.bounds byRoundingCorners:corners cornerRadii:radii];
    
    shapeView.shapeLayer.lineWidth = 1;
    shapeView.shapeLayer.fillColor = [UIColor clearColor].CGColor;
    shapeView.shapeLayer.strokeColor = [UIColor blueColor].CGColor;
    shapeView.shapeLayer.path = bPath.CGPath;

效果:框架

2. CATextLayer

若是須要在圖層裏面顯示文字能夠藉助圖層代理直接使用CoreGraphics寫入圖層文本內容(UILabel精髓). 若是越過寄宿於圖層的視圖, 直接在圖層上操做, 那傢伙是至關至關至關的麻煩繁瑣的.佈局

CoreAnimation提供了CALayer的子類: CATextLayer, 它已圖層的形式包含了UIlabel幾乎全部的特性, 而且提供了一些新的特性.性能

CATextLayer使用Coretext, 渲染要比UIlabel快的多. 使用時候須要注意設置contentScale屬性, 不然在高分辨率屏幕會出現像素化的問題.測試

CATextLayer的string屬性, 是id類型的, 這樣你既能夠用NSString也能夠用NSAttributeString來指定文本, 使用NSAttributeString對象能夠方便的在CATextLayer上繪製文本, 而且設置相關的屬性. 因爲CATextLayer與UlLabel實現機制不一樣, 因此用CATextLayer和UIlabel渲染出的文本行距和字間距也是不盡相同的. 總的來講差別不大, 可是有差別.優化

2.1 UILabel的替代品

CATextLayer有比UILabel更好的性能, 可是不能像視圖同樣自動縮放和自動佈局, 一個好的方案是, 自定義Lable, 繼承自UILabel, 用CATextLayer做爲做爲UILabel的寄宿圖層. 這樣就CATextLayer能夠隨着視圖自動調整大小, 而且也不會有冗餘的寄宿圖了. 事實上, 這是能夠實現的. UIView 有個類方法叫 +layerClass, 咱們能夠重寫這個方法, 並返回CALayer的子類, 這樣UIView初始化時候回調用+layerClass方法, 並用它返回的類型來建立宿主圖層.動畫

例如:

+ (Class)layerClass {
    return [CAShapeLayer class];
}


- (CAShapeLayer *)shapeLayer {
    
    return (CAShapeLayer *)self.layer;
}

若是想在app裏面充分利用CALayer子類,用+layerClass來建立基於不一樣圖層的視圖是一個簡單可複用的方法。

3. CAGradientLayer

CAGradientLayer是用來生成兩種或者更多顏色平滑漸變的. 用CoreGraphics複製一個CAGradientLayer並將內容繪製到一個普通圖層的寄宿圖上也是可能的, 可是CAGradientLayer的真正好處是繪製使用了硬件加速, 運行效率會更快.

3.1 基礎漸變

Demo:

// CAGradientLayer
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    [self.view.layer addSublayer:gradientLayer];
    // 設置frame大小
    gradientLayer.frame = CGRectMake(120, 100, 100, 100);
    // 設置漸變的顏色  顏色必須用 __bridge id 橋接 CGColor, 不然無效
    gradientLayer.colors = @[(__bridge id)[UIColor redColor].CGColor,
                             (__bridge id)[UIColor purpleColor].CGColor,
                             (__bridge id)[UIColor blueColor].CGColor,
                             (__bridge id)[UIColor greenColor].CGColor];
    // 設置開始位置
    gradientLayer.startPoint = CGPointMake(0, 0);
    // 設置結束位置
    gradientLayer.endPoint = CGPointMake(1, 1);

3.2 多重漸變

默認顏色是按照比例均勻的漸變的, 可是咱們能夠經過一個叫 locations 的數組屬性控制不一樣顏色的位置, 注意 locations中數組大小要和colors數組大小保持一致, 不然獲得空白的漸變.

Demo:

// CAGradientLayer
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    [self.view.layer addSublayer:gradientLayer];
    // 設置frame大小
    gradientLayer.frame = CGRectMake(120, 100, 100, 100);
    // 設置漸變的顏色  顏色必須用 __bridge id 橋接 CGColor, 不然無效
    gradientLayer.colors = @[(__bridge id)[UIColor redColor].CGColor,
                             (__bridge id)[UIColor purpleColor].CGColor,
                             (__bridge id)[UIColor greenColor].CGColor];
    // 設置開始位置
    gradientLayer.startPoint = CGPointMake(0, 0);
    // 設置結束位置
    gradientLayer.endPoint = CGPointMake(1, 1);
    // 設置漸變顏色的位置
    gradientLayer.locations = @[@0.5, @0.75, @1];

代碼如上, 測試發現, 三個數值的意義是, 第一個數值表明, 第一種顏色開始漸變過渡到第二種顏色的單位座標; 第二個數值表明, 第二種顏色向第一種顏色方向和向第三種顏色方向開始漸變的單位座標; 第三個數值表明, 第三種顏色開始和第二種顏色過渡漸變的單位座標.

4. CAReplicatorLayer

顧名思義, 重複圖層. CAReplicatorLayer的目的是爲了高效生成許多類似的圖層.

上代碼:

// 重複圖層
    CAReplicatorLayer *rLayer = [CAReplicatorLayer layer];
    rLayer.frame = CGRectMake(0, 220, self.view.bounds.size.width, 350);
    [self.view.layer addSublayer:rLayer];
    rLayer.backgroundColor = [UIColor lightGrayColor].CGColor;
    
    // 重複次數
    rLayer.instanceCount = 10;
    
    //爲每一個對象註冊一個transform
//    CATransform3D transform = CATransform3DMakeTranslation(30, 0, 0);
//    rLayer.instanceTransform = transform;
    
    CATransform3D transform = CATransform3DIdentity;
    transform = CATransform3DTranslate(transform, 0, 20, 0);
    transform = CATransform3DRotate(transform, M_PI / 5.0, 0, 0, 1);
    transform = CATransform3DTranslate(transform, 0, -20, 0);
    rLayer.instanceTransform = transform;
    
    rLayer.instanceRedOffset = -0.1;
    rLayer.instanceGreenOffset = -0.1;
    rLayer.instanceBlueOffset = 0.1;
    
    
    CALayer *layer = [CALayer layer];
    layer.backgroundColor = [UIColor whiteColor].CGColor;
//    layer.frame = CGRectMake(10, 10, 20, 20);
    layer.frame = CGRectMake(rLayer.position.x-10, 140, 20, 20);
    [rLayer addSublayer:layer];

效果:

剛開始看這一節時候, 看了幾遍, 有點不知所云, 上個demo, 而後一切都清晰明瞭了.

如上代碼所示, 先建立一個CAReplicatorLayer實例, 設置相關的參數, 而後被添加到這個實例上面的subLayer就會發生相應的變化.

在項目實戰中, 若是咱們直接使用CAReplicatorLayer作全部的操做, 也會出現不少限制, 好比不能自動適配, 不能隨意更改大小等, 我認爲正確的作法是, 使用CAReplicatorLayer做爲一個視圖的寄宿layer, 這樣咱們能夠像操做普通視圖同樣操做CAReplicatorLayer對象, 同時咱們能夠把CAReplicatorLayer實例相關的變換和操做都封裝到自定義的視圖中去, 咱們只須要向視圖中添加視圖或者圖層, 就會出現咱們想要的效果. 代碼以下.

// 重複圖層
    TTReplicatorView *replicatorView = [[TTReplicatorView alloc] initWithFrame:CGRectMake(0, 220, self.view.bounds.size.width, 350)];
    [self.view addSubview:replicatorView];
    replicatorView.backgroundColor = [UIColor lightGrayColor];
    
    
    CAReplicatorLayer *rLayer = replicatorView.replicatorLayer;
    
    // 重複次數
    rLayer.instanceCount = 10;
    
    CATransform3D transform = CATransform3DIdentity;
    transform = CATransform3DTranslate(transform, 0, 20, 0);
    transform = CATransform3DRotate(transform, M_PI / 5.0, 0, 0, 1);
    transform = CATransform3DTranslate(transform, 0, -20, 0);
    rLayer.instanceTransform = transform;
    
    rLayer.instanceRedOffset = -0.1;
    rLayer.instanceGreenOffset = -0.1;
    rLayer.instanceBlueOffset = 0.1;
    
    
    UIView *subView = [[UIView alloc] init];
    [replicatorView addSubview:subView];
    subView.frame = CGRectMake(rLayer.position.x-10, 140, 20, 20);
    subView.backgroundColor = [UIColor redColor];

測試結論:

  • CAReplicatorLayer對象上能夠放置其它的視圖或者圖層對象, 這時候CAReplicatorLayer對象的變換對子視圖的子視圖同樣有相同的效果.
  • 若是變換時候CAReplicatorLayer子圖層的位置超出了CAReplicatorLayer實例的bounds, 仍是會正常展現出來的.

4.1 反射

CAReplicatorLayer圖層的一個重要應用就是反射

// 反射
    TTReplicatorView *reflectView = [[TTReplicatorView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(replicatorView.frame)+30, CGRectGetWidth(self.view.frame), 200)];
    [self.view addSubview:reflectView];
    reflectView.layer.borderWidth = 1;
    reflectView.layer.borderColor = [UIColor lightGrayColor].CGColor;
    reflectView.clipsToBounds = YES;
//
    CAReplicatorLayer *reflectLayer = reflectView.replicatorLayer;
    reflectLayer.instanceCount = 2;
    reflectLayer.instanceAlphaOffset = -0.6;
//
    CATransform3D transform2 = CATransform3DMakeTranslation(0, 80, 0);
    transform2 = CATransform3DRotate(transform2, M_PI, 1, 0, 0);
    reflectLayer.instanceTransform = transform2;
    
    
    UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"111.jpg"]];
    [reflectView addSubview:imgView];
    imgView.frame = CGRectMake(20, 60, 100, 80);
    imgView.clipsToBounds = YES;
    imgView.contentMode = UIViewContentModeScaleAspectFill;

測試反射以後發現, CATransform3D做用在CAReplicatorLayer對象上以後, 並非想要的那種效果, 目前還沒搞明白是爲何..

5. CAScrollLayer

我的以爲, 並無什麼卵用 ......

第一次看CoreAnimation, 也不可能徹底看完看懂啊, 這個類就是那個被省略的部分 ~

6. CATransformLayer

http://wiki.jikexueyuan.com/project/ios-core-animation/special-layer.html

正常狀況下, 全部的圖層都會將它的子圖層平面化到一個場景中, 可是 CATransformLayer 並不會平面化它的子圖層, 因此若是須要構建有層級關係的結構時候就很是的有用. 詳見文檔, 很少解釋.

7. CATiledLayer

好比有一張超大的圖片, 若是將圖片一次性徹底載入整個圖片到內存中有點不靠譜, 或者至關的慢, 會影響性能, 這時候一個好的解決方法就是 CATiledLayer , 它也能夠將大圖裁剪成n個小圖, 而後載入展現出來,

待看

8. CAEmitterLayer

這是一個高性能的粒子引擎, 能夠被用來建立實時粒子動畫, 好比: 煙霧, 火, 雨等效果.

待研究

9. CAEAGLLayer

iOS設備上繪圖性能最高的就是OpenGL了, 可是它也是難以想象的複雜. iOS5中蘋果引入了新的框架, CLKit, 提供一個CLKView 的UIView的子類, 能夠處理大部分設置和繪圖工做, 可是OpenGL繪圖緩衝的底層可配置選項仍是要經過CAEAGLLayer來完成, 它是CALayer的子類, 用來顯示任意的OpenGL圖形.

10. AVPlayerLayer

這個不是CoreAnimation框架的一部分, 但也緊密的聯繫在一塊兒的. AVPlayerLayer能夠用來在iOS設備上播放視頻, 它是高級接口 MPMoviePlayer 的底層實現, 提供了顯示視頻的底層控制. AVPlayerLayer使用起來也是很是簡單的, 使用時候須要先導入 #import <AVFoundation/AVFoundation.h> 框架.

待研究

11. 總結

須要記住的是 CALayer的用處是很大的, 並且它並無爲全部可能的場景進行優化, 爲了得到CoreAnimation更好的性能, 須要選擇使用合適的CALayer子類.

相關文章
相關標籤/搜索