为什么要学习CALayer

之前只是了解一些基本概念和一些理论知识。

Core Animation是直接作用在CALayer上的(并非UIView上)非常强大的跨Mac OS X和iOS平台的动画处理API.Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。所以我们要学习CALayer

什么是CALayer(图层)?

Layers Provide the Basis for Drawing and Animations(Layers是绘图和动画的基础)

CALayer(图层) 是屏幕上的一个具有可见内容的矩形区域,每个UIView都有一个根CALayer,其所有的绘制(视觉效果)都是在这个layer上进行的。当然我们也可以单独创建CALayer

UIView中有一个CALayer类型的layer,并且是readonly类型

@property(nonatomic,readonly,strong) CALayer *layer; // returns view's layer. Will always return a non-nil value. view is layer's delegate

如果要更改 UIView 的 CALayer,要引用:#import \.

下面先推荐两篇文章: 文章 1:原理介绍简单介绍; 2:官方文章

CALayer 和 UIView的区别和联系

在简书上看到一篇文章讲的很不错:CALayer 和 UIView的区别和联系,可以看看

其实UIView之所以能显示在屏幕上,完全是因为它内部的一个图层,在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个层

我们在 [view initWithFrame] 的时候调用私有方法
【UIView _createLayerWithFrame】去创建 CALayer。

UIView 是 CALayer 的CALayerDelegate,代理方法内部[UIView(CALayerDelegate) drawLayer:inContext]调用 UIView 的 DrawRect方法,从而绘制出了 UIView 的内容

当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成了UIView的显示

换句话说,UIView本身不具备显示的功能,拥有显示功能的是它内部的图层。

继承关系

  • UIView
NS_CLASS_AVAILABLE_IOS(2_0) @interface UIView : UIResponder <NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusEnvironment>
+ (Class)layerClass; // default is [CALayer class]. Used when creating the underlying layer for the view.

UIView的继承结构为: UIResponder : NSObject

  • CALayer
@interface CALayer : NSObject <NSCoding, CAMediaTiming>
```
CALayer的继承结构为:NSObject
- 总结
1. UIViewCALayer都是的老祖都是NSObjet。不仅这两个类继承于NSObject,几乎所有的类都是继承于NSObject.
2. 因为UIResponder是用来响应事件的,也就是UIView可以响应用户事件。而CALayer继承于NSObject,缺少了UIResponder类,所以CALayer悲催的不能响应任何用户事件。
### 所属框架
- UIView是在 /System/Library/Frameworks/UIKit.framework中定义的。官方对[***UIKit.framework***](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIKit_Framework/)解释如下:
> The UIKit framework (UIKit.framework) provides the crucial infrastructure needed to construct and manage iOS apps. This framework provides the window and view architecture needed to manage an app’s user interface, the event handling infrastructure needed to respond to user input, and the app model needed to drive the main run loop and interact with the system.
大体的意思就是UIKit主要是用来构建和管理用户界面,并且是可以响应事件的(得意与UIView的父类UIResponder,至于UIResponderd的实现原理不是这次分析的目的,有兴趣的可以自行研究里面原理)
既然UIKit是用来构建和管理用户界面的。那他是通过什么方式绘制这些图片、文字之类的信息的呢?
iOS中的2D图像绘制都是通过QuartzCore.framework实现的。难道是通过QuartzCore.framework实现的?那又是通过什么方式和QuartzCore.framework联系起来的呢?后面我会验证...
- CALayer是在/System/Library/Frameworks/QuartzCore.framework定义的。而且CALayer作为一个低级的,可以承载绘制内容的底层对象出现在该框架中。
- uiview和CALayer都可以显示图片文字等信息。难道apple提供了,两套绘图机制吗?不会。
大家都知道QuartzCore是IOS中提供图像绘制的基础库。并且CALayer是定义该框架中。
UIView是基于CALayer的高层封装。The view system in iOS is built directly on top of Core Animation layers.
### layer内部维护着三份layer tree(上一篇有提到)
- 第一份,模型树(Model Layer Tree) 就是代码可以操纵的,例如更改Layer的属性等等就在这一份。存储的是模态对象,也是我们通常处理的对象,比如layer.position = CGPointMake(10.0,10.0)
- 第二份,呈现树(Presentation layer Tree) 这是一个中间层,呈现树的属性和动画运行过程中界面看到的是一致的,也可以说这层是Layer在屏幕中的真实位置。存储的是正在执行的动画的当前状态,是个动态的树,由这个树来获取当前动画运行到哪里。
- 第三份,渲染树(Rendering Layer Tree) 渲染树是私有的,开发者无法访问到。渲染树是对呈现树的数据进行渲染,为了不阻塞主线程,渲染的过程是在单独的进程或线程中进行的,所以你会发现Animation的动画并不会阻塞主线程.
这三点对后续Core Animation的深入理解很重要。
### 渲染
当更新层的值(上面第一份更新的值,第二份或第三份没有及时改变),改变不能立即显示在屏幕上。当所有的层都准备好时,CALayer可以调用下面方法来重绘显示。

setNeedsDisplay
setNeedsDisplayInRect:

### 创建过程
#### CALayer 提供CALayer内容的三种方式
##### 1.把一个图像对象直接赋值给contents属性(这是提供CALayer内容的最好方式)

CALayer * imageLayer = [CALayer layer];
imageLayer.bounds = CGRectMake(0,0,200,100);
imageLayer.position = CGPointMake(200,200);
imageLayer.contents = (id)[UIImage imageNamed:@”psb.png”].CGImage;
imageLayer.contentsGravity = kCAGravityResizeAspect;
[self.view.layer addSublayer:imageLayer];

效果如下:![](http://i4.tietuku.com/77d1d29aaf45413f.jpg)
##### 2.设置Delegate
```
@interface NSObject (CALayerDelegate)
/* If defined, called by the default implementation of the -display
* method, in which case it should implement the entire display
* process (typically by setting the `contents' property). */
- (void)displayLayer:(CALayer *)layer;
/* If defined, called by the default implementation of -drawInContext: */
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
/* Called by the default -layoutSublayers implementation before the layout
* manager is checked. Note that if the delegate method is invoked, the
* layout manager will be ignored. */
- (void)layoutSublayersOfLayer:(CALayer *)layer;

测试代码:

- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
NSLog(@"- (instancetype)initWithFrame:(CGRect)frame");
[self.layer setNeedsDisplay];
}
return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(@"- (void)drawRect:(CGRect)rect");
// Drawing code.
//获得处理的上下文
CGContextRef context = UIGraphicsGetCurrentContext();
//设置线条样式
CGContextSetLineCap(context, kCGLineCapSquare);
//设置线条粗细宽度
CGContextSetLineWidth(context, 1.0);
//设置颜色
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
//开始一个起始路径
CGContextBeginPath(context);
//起始点设置为(0,0):注意这是上下文对应区域中的相对坐标,
CGContextMoveToPoint(context, 0, 0);
//设置下一个坐标点
CGContextAddLineToPoint(context, 100, 100);
//设置下一个坐标点
CGContextAddLineToPoint(context, 0, 150);
//设置下一个坐标点
CGContextAddLineToPoint(context, 50, 180);
//连接上面定义的坐标点
CGContextStrokePath(context);
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
NSLog(@"- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx");
//来绘制图层
CGContextSaveGState(ctx);
//a.翻转
CGContextScaleCTM(ctx, 1.0, -2.0);
//b.平移
CGContextTranslateCTM(ctx, 0, -self.bounds.size.height);
UIImage *image = [UIImage imageNamed:@"psb.png"];
CGContextDrawImage(ctx, CGRectMake(50, 50, 100, 100), image.CGImage);
CGContextRestoreGState(ctx);
//画青色的园
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
CGContextSetRGBFillColor(ctx, 0.0, 1.0, 1.0, 1.0);
CGContextDrawPath(ctx, kCGPathFill);
//画蓝色的园
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
CGContextSetRGBFillColor(ctx, 1.0, 0.0, 1.0, 1.0);
CGContextDrawPath(ctx, kCGPathFill);
}
//如果实现了这个代理方法,上面那个就不会执行了
- (void)displayLayer:(CALayer *)layer{
NSLog(@"- (void)displayLayer:(CALayer *)layer");
}

运行结果

2016-03-03 02:02:47.829 JYCoreAnimationDemo[1801:145582] - (instancetype)initWithFrame:(CGRect)frame
2016-03-03 02:02:47.831 JYCoreAnimationDemo[1801:145582] - (void)displayLayer:(CALayer *)layer

这是继承UIView的TestView并没有设置Layer.delegate;为什么有那两个代理方法,不很奇怪吗?后面会解释…

当layer中的内容是需要动态改变的时候,可以使用delegate来实现
两个代理方法:

displayLayer:如果代理实现了这个方法,那么要绘制一个bitmap(位图),然后赋值给contents属性(参考方式1
drawLayer:inContext:如果代理实现了这个方法,Core Animation提供一个context来生成bitmap(位图),你所做的只是把想要的内容绘制到context
注意:代理必须至少实现两个代理方法其中的一个,如果都实现,则调用
displayLayer:
自定义UIView重写Layer代理方法时。
- (void)drawRect:(CGRect)rect;是不会执行的。会跳过
3.使用draw:inContext实现自定义重新绘制

测试代码:

自定义UIView

- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
NSLog(@"- (instancetype)initWithFrame:(CGRect)frame");
TestCALayer *myLayer = [TestCALayer layer];
[myLayer setBounds:self.bounds];
[myLayer setPosition:CGPointMake(100, 100)];
[myLayer setBackgroundColor:[UIColor redColor].CGColor];
[self.layer addSublayer:myLayer];
self.myLayer = myLayer;
[self.myLayer setNeedsDisplay];
}
return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(@"- (void)drawRect:(CGRect)rect");
// Drawing code.
//获得处理的上下文
CGContextRef context = UIGraphicsGetCurrentContext();
//设置线条样式
CGContextSetLineCap(context, kCGLineCapSquare);
//设置线条粗细宽度
CGContextSetLineWidth(context, 1.0);
//设置颜色
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
//开始一个起始路径
CGContextBeginPath(context);
//起始点设置为(0,0):注意这是上下文对应区域中的相对坐标,
CGContextMoveToPoint(context, 0, 0);
//设置下一个坐标点
CGContextAddLineToPoint(context, 100, 100);
//设置下一个坐标点
CGContextAddLineToPoint(context, 0, 150);
//设置下一个坐标点
CGContextAddLineToPoint(context, 50, 180);
//连接上面定义的坐标点
CGContextStrokePath(context);
}

自定义CALayer

-(void)drawInContext:(CGContextRef)ctx{
//来绘制图层
CGContextSaveGState(ctx);
//a.翻转
CGContextScaleCTM(ctx, 1.0, -2.0);
//b.平移
CGContextTranslateCTM(ctx, 0, -self.bounds.size.height);
UIImage *image = [UIImage imageNamed:@"psb.png"];
CGContextDrawImage(ctx, CGRectMake(50, 50, 100, 100), image.CGImage);
CGContextRestoreGState(ctx);
//画青色的圆
CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100));
CGContextSetRGBFillColor(ctx, 0.0, 1.0, 1.0, 1.0);
CGContextDrawPath(ctx, kCGPathFill);
NSLog(@"-(void)drawInContext:(CGContextRef)ctx");
//画蓝色的圆
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
CGContextSetRGBFillColor(ctx, 1.0, 0.0, 1.0, 1.0);
CGContextDrawPath(ctx, kCGPathFill);
}

运行结果如下:

2016-03-03 02:17:15.739 JYCoreAnimationDemo[1857:152533] - (instancetype)initWithFrame:(CGRect)frame
2016-03-03 02:17:15.742 JYCoreAnimationDemo[1857:152533] - (void)drawRect:(CGRect)rect
2016-03-03 02:17:15.756 JYCoreAnimationDemo[1857:152533] -(void)drawInContext:(CGContextRef)ctx

根据打印的log看出顺序 注意:

1.如果使用自定义图层绘图时,UIView本身的DrawRect方法内的绘图结果将被layer的绘图结果覆盖。
2.如果使用CALayer绘图,就不要再写drawRect方法
3.一定要调用[self.myLayer setNeedsDisplay];否则无法绘图。

绘制 CGContextRef内容就属于Core Graphics框架(Quartz2D绘图最核心)部分了(后面文章会总结)

UIView 创建展示过程,

前面留了一个疑问:UIView是用来构建界面的,QuartzCore是用来绘制图片、文字的。那它们是怎么建立连接的?

其实上面说了UIView是对CALayer的高级封装。从上面简书博客中我了解到:
我们在 [view initWithFrame] 的时候调用私有方法

[UIView _createLayerWithFrame]去创建 CALayer

前面我们测试代码中没有给Layer的Delegate设置给自定义UIView。其实是因为UIView本身是CALayer的Delegate,遵循CALayerDelegate的方法。

其实一个view add到另一个view的创建过程为:

[view initWithFrame];
[view _createLayerWithFrame]去创建 layer,并且根据frame设置CALayer的bounds、frame、postion等.同时layer的Delegate设置为view;这样view就可以遵循代理方法,可以重写Layer属性。
[layer setNeedDisplay];绘制图片、文字等信息,会自动生成context
view会实现drawLayer方法,此方法会调用super的drawrect,当然我们可以重写来重新绘制,
在drawrect方法中获取的context,就是layer中生成context。所以我们可以在drawrect重新绘制视图

UIView调用drawRect:

  • 1.在UIView每次设置或更改frame的时候自动调用drawRect:
  • 2.直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0.

若使用UIView绘图 只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个invalidate的ref并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay 或者 setNeedsDisplayInRect ,让系统自动调该方法。

若使用calayer绘图 只能在把一个图像对象直接赋值给contents属性,drawInContext: 中(类似鱼drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法。

最后总结

发之于肤,血之于肉,灵之于魄,男人之于肾的关系。依存的关系

UIView来自CALayer,高于CALayer,是CALayer高层实现与封装。UIView的所有特性来源于CALayer支持。


CALayer 的一些重要属性

在iOS上面,图层的坐标系原点位于左上角,原点向下和向右为正值。

bounds

指定图层的大小(bounds.size)和图层的原点(bounds.origin)。当你重写图层的重画方法的时候,bounds的原点可以作为图形上下文的原点。

anchorPoint

图层的anchorPoint属性是一个CGPoint值,它指定了一个基于图层bounds的符合位置坐标系的位置。锚点(anchor point)指定了bounds相对于position的值,同时也作为变换时候的支点。锚点使用单元空间坐标系表示,(0.0,0.0)点接近图层的原点,而(1.0,1.0)是原点的对角点。改变图层的父图层的变换属性(如果存在的话)将会影响到anchorPoint的方向,具体变化取决于父图层坐标系的Y轴。

position

指定图层相当于它父视图的位置,该值基于父视图图层的坐标系

frame

图层拥有一个隐式的frame,它是position,bounds,anchorPoint和transform属性的一部分。设置新的frame将会相应的改变图层的position和bounds属性,但是frame本身并没有被保存。但是设置新的frame时候,bounds的原点不受干扰,bounds的大小变为frame的大小,即bounds.size=frame.size。图层的位置被设置为相对于锚点(anchor point)的适合位置。当你设置frame的值的时候,它的计算方式和position、bounds、和anchorPoint的属性相关.

zPosition

图层位于Z轴上的位置

backgroundColor

图层背景颜色

borderColor

图层边框颜色

borderWidth

图层的边框宽度

cornerRadius

图层的圆角

masksToBounds

父图层是否对超过父视图范围的子图层部分进行裁剪 设置阴影不会有显示效果。这个属性很重要

opacity

图层的透明度0~1,默认是1

shadowOffset

图层的阴影 在 X 和 Y 轴 上延伸的方向,即 shadow 的偏移量

shadowColor

图层的阴影背景颜色

shadowPath

设置图层背景(shodow)的位置

shadowOpacity = 1.0;

图层阴影的透明效果0~1,默认是0.f

shadowRadius

图层阴影 的渐变距离,从外围开始,往里渐变 shadowRadius 距离(圆角)

transform

设置3D效果

contents

设置内容 一般用来设置 layer 的图片


CALayer的添加删除方法

添加Layer到父图层的子图层数组中,如果Layer已经存在父图层,则先从之前父图层移除,再添加到新父图层。
 - (void)addSublayer:(CALayer *)layer;

插入图层到父图层的索引位置(插入前会事先移动原索引的子图层)
- (void)insertSublayer:(CALayer *)layer atIndex:(unsigned)idx;

在Layer下面插入一个Layer,如果Layer已经存在父图层,则先从之前父图层移除,再添加到新父图层。
- (void)insertSublayer:(CALayer *)layer below:(nullable CALayer *)sibling;

在Layer上面插入一个Layer,如果Layer已经存在父图层,则先从之前父图层移除,再添加到新父图层。
 - (void)insertSublayer:(CALayer *)layer above:(nullable CALayer *)sibling;

 替换父图层索引位置的子图层(插入前会事先删除原索引的子图层) 
 - (void)replaceSublayer:(CALayer *)layer with:(CALayer *)layer2;

 从父图层删除
 - (void)removeFromSuperlayer;

测试代码

- (void)addSubLayer{
CALayer *layer = [[CALayer alloc] init];
layer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer];
layer.bounds = CGRectMake(0, 0, 100, 100);
layer.anchorPoint = CGPointMake(0, 0);
layer.position = CGPointMake(100, 100);
layer.frame = CGRectMake(0, 0, 100, 100);
layer.position = CGPointMake(100, 100);
layer.zPosition = 10.0;
layer.backgroundColor = [UIColororangeColor].CGColor;
layer.borderColor = [UIColor purpleColor].CGColor;
layer.borderWidth = 5.0;
layer.cornerRadius = 5.0;
layer.masksToBounds = NO;
layer.opacity = .9;
layer.shadowOffset = CGSizeMake(10.0, 10.0);
layer.shadowColor = [UIColor blackColor].CGColor;
layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 120, 120) cornerRadius:10.0].CGPath;
layer.shadowOpacity = 1.0;
layer.shadowRadius = 10.0;
//layer.transform = CATransform3DMakeRotation(M_PI_4, 1, 1, 0.5);//设置3D效果
}

效果如下:

CALayer的常用方法

+ (instancetype)layer;

  • 便捷创建图层函数。

    TestCALayer *layer = [TestCALayer layer];
    

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

  • 重写修改CALayer或其子类属性的默认值,key为属性名称,如果没有该属性则返回nil
//继承CALayer,重写这个方法
+ (nullable id)defaultValueForKey:(NSString *)key{
if ([key isEqualToString:@"anchorPoint"]) {
// anchorPoint的原默认值为(0.5, 0.5
return [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
}
else {
return [super defaultValueForKey:key];
}
}
//测试:
TestCALayer *layer = [TestCALayer layer];
NSLog(@"x:%f y:%f", layer.anchorPoint.x, layer.anchorPoint.y);
结果:
2016-03-04 14:26:12.071 JYCoreAnimationDemo[3570:1096007] x:1.000000 y:1.000000

+ (BOOL)needsDisplayForKey:(NSString *)key

  • 需要子类重写,当CALayer或其子类属性被修改时调用此方法。key为修改的属性名,当返回值为YES时系统自动调用-display 方法(暂时不是很明白,我测试没有调用)。
//测试代码
+ (BOOL)needsDisplayForKey:(NSString *)key
{
if ([@"time" isEqualToString:key])
{
return YES;
}
return [super needsDisplayForKey:key];
}
- (void)display
{
NSLog(@"time: %f", self.time);
}

+ (nullable id< CAAction >)defaultActionForKey:(NSString *)event

  • 返回当前类的默认操作。

- (instancetype)init

  • 初始化

- (instancetype)initWithLayer:(id)layer

  • 复制一个图层

转换坐标点

  • - (CGPoint)convertPoint:(CGPoint)p fromLayer:(nullable CALayer *)l

  • - (CGPoint)convertPoint:(CGPoint)p toLayer:(nullable CALayer *)l

转换矩形

  • - (CGRect)convertRect:(CGRect)r fromLayer:(nullable CALayer *)l

  • - (CGRect)convertRect:(CGRect)r toLayer:(nullable CALayer *)l

转换CAMediaTiming协议的相对时间

  • - (CFTimeInterval)convertTime:(CFTimeInterval)t fromLayer:(nullable CALayer *)l

  • - (CFTimeInterval)convertTime:(CFTimeInterval)t toLayer:(nullable CALayer *)l

- (nullable CALayer *)hitTest:(CGPoint)p

  • 返回点所在的最上层的图层

- (BOOL)containsPoint:(CGPoint)p

  • 判断点是否在图层范围内

- (void)display

  • 重新加载该层的内容。
  • 不要直接调用此方法。layer会自动在适当的适合调用此方法。
  • 子类可以覆盖此方法,并用它来修改图层。

标记图层的内容为需要更新(调用此方法将导致重新缓存内容层)

  • - (void)setNeedsDisplay
  • - (void)setNeedsDisplayInRect:(CGRect)r

- (void)drawInContext:(CGContextRef)ctx

  • 使用指定的图形上下文绘制图层的内容。

- (void)renderInContext:(CGContextRef)ctx

  • 将各层呈现到指定的上下文。

- (void)setNeedsLayout

  • 图层布局无效,并标记需要更新。
  • 可以调用此方法以指示子图层的布局发生了变化,必须进行更新。
  • 子图层的添加或删除会自动调用此方法。

- (void)addAnimation:(CAAnimation)anim forKey:(nullable NSString )key

  • 将指定动画对象添加到渲染树上

- (void)removeAllAnimations

  • 移除该图层上的所有动画。

- (void)removeAnimationForKey:(NSString *)key

  • 移除指定key对应的动画。

- (nullable NSArray< NSString> )animationKeys

  • 获取当前图层所有动画的key。

- (nullable CAAnimation)animationForKey:(NSString )key

  • 返回与key对应的动画对象,如果没有则返回nil。

CALayerDelegate方法

- (void)displayLayer:(CALayer *)layer

  • 更新图层时回调

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx

  • 绘制图层时回调

- (void)layoutSublayersOfLayer:(CALayer *)layer

  • 子图层布局时回调

- (nullable id< CAAction>)actionForLayer:(CALayer)layer forKey:(NSString )event

  • 执行指定操作是回调

常用的CALayer子类(后面文章会深入了解)

SubLayer 介绍
CAEmitterLayer 发射器层,用来控制粒子效果
CAGradientLayer 梯度层,颜色渐变
CAEAGLayer CAEAGLayer
CAReplicationLayer 用来自动复制sublayer
CAScrollLayer 用来管理可滑动的区域
CAShapeLayer 绘制立体的贝塞尔曲线
CATextLayer 可以绘制AttributeString
CATiledLayer 用来管理一副可以被分割的大图
CATransformLayer 用来渲染3D layer的层次结构