iOS图层树(图层的树状结构)
CoreAnimation
屏幕上不同的可视内容(可分解成各个独立的图层)通过CoreAnimation引擎组合显示在屏幕上,存在图层树体系中.而这个树就是UIKit所能看到的一个个控件的基础
CALayer
CALayer类和UIView相似,两者都是存储在图层树中的矩形块,都可以包含内容,eg:文本,图片或者背景色,或者管理子视图,也可以通过一些方法和属性来做动画和变换.两者不同之处:UIView处理用户交互,CALayer则不处理交互
CALayer属性
contents
CaLayer这个属性contents,这个属性的类型被定义为id,但是如果这个值被赋值的类型不是CGImage,所得到的图层会是空白的.所以iOS开发中赋值类型经常是CGImage,其他类型没有什么意义.
contents这个奇怪的表现是由Mac OS的历史原因造成的。它之所以被定义为id类型,是因为在Mac OS系统上,这个属性对CGImage和NSImage类型的值都起作用。如果你试图在iOS平台上将UIImage的值赋给它,只能得到一个空白的图层。一些初识Core Animation的iOS开发者可能会对这个感到困惑。
layer.contents = image.CGImage;
如果你是ARC环境,运行此语句,需要加(__bridge id),如果MRC则不需要.ARC环境下,如下:
layer.contents = (__bridge id)image.CGImage;
contentGravity
同UIImageView的ContentMonde属性.
contentGravity常用的值有:
• kCAGravityCenter
• kCAGravityTop
• kCAGravityBottom
• kCAGravityLeft
• kCAGravityRight
• kCAGravityTopLeft
• kCAGravityTopRight
• kCAGravityBottomLeft
• kCAGravityBottomRight
• kCAGravityResize
• kCAGravityResizeAspect
• kCAGravityResizeAspectFill
maskToBounds
同UIView的clipsToBounds属性,以用来决定是否显示超出边界的内容
contentsRect
contentsRect在app中最有趣的地方在于一个叫做image sprites(图片拼合)的用法。如果你有游戏编程的经验,那么你一定对图片拼合的概念很熟悉,图片能够在屏幕上独立地变更位置。抛开游戏编程不谈,这个技术常用来指代载入拼合的图片,跟移动图片一点关系也没有。
典型地,图片拼合后可以打包整合到一张大图上一次性载入。相比多次载入不同的图片,这样做能够带来很多方面的好处:内存使用,载入时间,渲染性能等等
2D游戏引擎入Cocos2D使用了拼合技术,它使用OpenGL来显示图片。不过我们可以使用拼合在一个普通的UIKit应用中,就是使用contentsRect
contentsCenter
看名字你可能会以为它可能跟图片的位置有关,不过这名字着实误导了你。contentsCenter其实是一个CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域。 改变contentsCenter的值并不会影响到寄宿图的显示,除非这个图层的大小改变了,你才看得到效果。
Custome Drawing
给contents赋CGImage的值不是唯一的设置寄宿图的方法。我们也可以直接用Core Graphics直接绘制寄宿图。能够通过继承UIView并实现-drawRect:方法来自定义绘制。
-drawRect: 方法没有默认的实现,因为对UIView来说,寄宿图并不是必须的,它不在意那到底是单调的颜色还是有一个图片的实例。如果UIView检测到-drawRect: 方法被调用了,它就会为视图分配一个寄宿图,这个寄宿图的像素尺寸等于视图大小乘以 contentsScale的值。
如果你不需要寄宿图,那就不要创建这个方法了,这会造成CPU资源和内存的浪费,这也是为什么苹果建议:如果没有自定义绘制的任务就不要在子类中写一个空的-drawRect:方法。
当视图在屏幕上出现的时候 -drawRect:方法就会被自动调用。-drawRect:方法里面的代码利用Core Graphics去绘制一个寄宿图,然后内容就会被缓存起来直到它需要被更新。虽然-drawRect:方法是一个UIView方法,事实上都是底层的CALayer安排了重绘工作和保存了因此产生的图片。
CALayerDelegate
CALayerDelegate是一个非正式协议,其实就是说没有CALayerDelegate @protocol可以让你在类里面引用啦.当需要被重绘时,CALayer会请求它的代理给他一个寄宿图来显示。它通过调用下面这个方法做到的:
- (void)displayLayer:(CALayerCALayer *)layer;
如果代理不实现-displayLayer:方法,CALayer就会转而尝试调用下面这个方法:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
举一个例子:
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *layerView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CALayer *calayer = [CALayer layer];
calayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
calayer.backgroundColor = [UIColor cyanColor].CGColor;
calayer.delegate = self;
calayer.contentsScale = [UIScreen mainScreen].scale;
[self.layerView.layer addSublayer:calayer];
[calayer display];
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
CGContextSetLineWidth(ctx, 10.0f);
CGContextSetStrokeColorWithColor(ctx, [UIColor orangeColor].CGColor);
CGContextStrokeEllipseInRect(ctx,layer.bounds);
}
图层
布局
UIView有三个比较重要的布局属性:frame,bounds和center,CALayer对应地叫做frame,bounds和position。为了能清楚区分,图层用了“position”,视图用了“center”,但是他们都代表同样的值。
Z坐标轴
CALayer存在于一个三维空间当中。除了我们已经讨论过的position和anchorPoint属性之外,CALayer还有另外两个属性,zPosition和anchorPointZ,二者都是在Z轴上描述图层位置的浮点类型。
zPosition最实用的功能就是改变图层的显示顺序
CAlayer响应链相关方法
CALayer并不关心任何响应链事件,所以不能直接处理触摸事件或者手势。但是它有一系列的方法帮你处理事件:-containsPoint:和-hitTest:。
拉伸过滤
minificationFilter和magnificationFilter属性.
当图片需要显示不同的大小的时候,有一种叫做拉伸过滤的算法就起到作用了。它作用于原图的像素上并根据需要生成新的像素显示在屏幕上。
CALayer为此提供了三种拉伸过滤方法,他们是:
• kCAFilterLinear
• kCAFilterNearest
• kCAFilterTrilinear
具体效果可以自己去比较,不一一列出来了