当
UIView
需要显示到屏幕上时,会调用drawrect
方法进行绘图,并且会将所有内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成了UIView
的显示
CALayer
CA:Core Animation
(核心动画)CALayer
是UIView
的显示图层,通过UIView
的layer
属性可以访问CALayer
负责视图中显示内容和动画UIView
负责监听和响应事件
@property(nonatomic,readonly,strong) CALayer *layer;
CALayer的基本属性
// 1.边框
redView.layer.borderWidth = 10;//边框厚度
redView.layer.borderColor = [UIColor redColor].CGColor;//边框颜色
// 2.阴影 图层阴影并不总是方的,而是从图层内容的形状继承而来,可以是不规则的
redView.layer.shadowOffset = CGSizeMake(100,100);//阴影偏移量 CGSizeZero
redView.layer.shadowColor = [UIColor redColor].CGColor;//阴影颜色
redView.layer.shadowRadius = 50;//阴影半径
redView.layer.shadowOpacity = 1;//阴影不透明度为1
// 3.圆角
redView.layer.cornerRadius = 50;//边框厚度
redView.layer.masksToBounds = YES;//超出范围不显示
// 4.bounds
redView.layer.bounds = CGRectMake(0,0,200,200);//直接设置wdxy
redView.layer.frame = CGRectMake(0,0,200,200);//不建议设置wd
redView.layer.position = CGPointMake(0,0)//设置中心
// 5.backgroundColor也是layer的属性
- 给
View
的layer
添加layer
:可以实现一个View
上面有多个颜色方块
CALayer *layer = [[CALayer alloc] init];
layer.backgroundColor = [UIColor redColor].CGColor;
layer.position = CGPointMake(200,200);
layer.bounds = CGRectMake(0,0,100,100);
[self.view.layer addSublayer:layer];
-
layer
自带隐式动画:带Animateble
注释的属性,修改自带动画,透明度,大小,位置等 -
view
的根layer
是没有隐式动画 -
禁用隐式动画(事务)
// 都是类方法
[CATransaction begin];// 开启事务
[CATransaction setDisableActions:YES];// 禁止
// 这里是生效的区域
[CATransaction commit];// 提交事务
CALayer的锚点(定位点)
CALayer的其他属性
contents
:显示图层,可以设置图片
layer.contents = (__bridge id)image.CGImage;
contentsGravity
:设置对齐模型,对应UIView
的contentMode
,但是它是一个NSString
类型,而不是像对应的UIKit
部分,那里面的值是枚举
layer.contentsGravity = kCAGravityResizeAspect;
contentsScale
:缩放比例
// 获取图片对应的scale
layer.contentsScale = image.scale;
// 或者获取屏幕的scale
layer.contentsScale = [UIScreen mainScreen].scale;
maskToBounds
:对应UIView
的clipsToBounds
layer.maskToBounds = YES;
contentsRect
:CALayer
的contentsRect
属性允许我们在图层边框里显示寄宿图的一个子域
layer.contentsRect = CGRectMake(0, 0, 0.5, 0.5);
contentsCenter
:它定义了一个固定的边框和一个在图层上可拉伸的区域
layer.contentsCenter = CGRectMake(0.25, 0.25, 0.5, 0.5);
shadowPath
:用于自定义阴影图案,如果是一个矩形或者是圆,用CGPath
会相当简单明了。但是如果是更加复杂一点的图形,UIBezierPath
类会更合适
//enable layer shadows
self.layerView1.layer.shadowOpacity = 0.5f;
self.layerView2.layer.shadowOpacity = 0.5f;
//create a square shadow
CGMutablePathRef squarePath = CGPathCreateMutable();
CGPathAddRect(squarePath, NULL, self.layerView1.bounds);
self.layerView1.layer.shadowPath = squarePath;
CGPathRelease(squarePath);
//create a circular shadow
CGMutablePathRef circlePath = CGPathCreateMutable();
CGPathAddEllipseInRect(circlePath, NULL, self.layerView2.bounds);
self.layerView2.layer.shadowPath = circlePath;
CGPathRelease(circlePath);
shouldRasterize
:组透明的效果,如果它被设置为YES,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片,这样就没有透明度混合的问题了
layer.shouldRasterize = YES;
CALayer绘制图案
- 通过继承
UIView
并实现drawRect:
方法来自定义绘制 - 通过代理方法实现
// CALayerDelegate协议
// 当需要被重绘时,CALayer会请求它的代理给他一个寄宿图来显示。它通过调用下面这个方法做到的:
- (void)displayLayer:(CALayerCALayer *)layer;
// 趁着这个机会,如果代理想直接设置contents属性的话,它就可以这么做,不然没有别的方法可以调用了。如果代理不实现-displayLayer:方法,CALayer就会转而尝试调用下面这个方法:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;
//create sublayer
CALayer *blueLayer = [CALayer layer];
blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
blueLayer.backgroundColor = [UIColor blueColor].CGColor;
//set controller as layer delegate
blueLayer.delegate = self;
//ensure that layer backing image uses correct scale
blueLayer.contentsScale = [UIScreen mainScreen].scale; //add layer to our view
[self.layerView.layer addSublayer:blueLayer];
//force layer to redraw
[blueLayer display];
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
//draw a thick red circle
CGContextSetLineWidth(ctx, 10.0f);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextStrokeEllipseInRect(ctx, layer.bounds);
}
Hit Testing
CALayer
并不关心任何响应链事件,所以不能直接处理触摸事件或者手势。但是它有一系列的方法帮你处理事件:-containsPoint:
和-hitTest:
containsPoint
:判断是否在内部,需要手动去转化对应的坐标系
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//get touch position relative to main view
CGPoint point = [[touches anyObject] locationInView:self.view];
//convert point to the white layer's coordinates
point = [self.layerView.layer convertPoint:point fromLayer:self.view.layer];
//get layer using containsPoint:
if ([self.layerView.layer containsPoint:point]) {
//convert point to blueLayer’s coordinates
point = [self.blueLayer convertPoint:point fromLayer:self.layerView.layer];
if ([self.blueLayer containsPoint:point]) {
NSLog(@"Inside Blue Layer");
} else {
NSLog(@"Inside White Layer");
}
}
}
hitTest
:不需要动去转化对应的坐标系,返回所在的layer
或者nil
注意当调用图层的-hitTest:
方法时,测算的顺序严格依赖于图层树当中的图层顺序(和UIView
处理事件类似)。zPosition
属性可以明显改变屏幕上图层的顺序,但不能改变事件传递的顺序,也意味着改变zPosition
,将可能不能够检测到最前方的视图点击事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//get touch position
CGPoint point = [[touches anyObject] locationInView:self.view];
//get touched layer
CALayer *layer = [self.layerView.layer hitTest:point];
//get layer using hitTest
if (layer == self.blueLayer) {
NSLog(@"Inside Blue Layer");
} else if (layer == self.layerView.layer) {
NSLog(@"Inside White Layer");
}
}
CALayer图层蒙版
//create mask layer
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = self.layerView.bounds;
maskLayer.contents = (__bridge id)[UIImage imageNamed:@"Cone.png"].CGImage;
//apply mask to image layer
self.imageView.layer.mask = maskLayer;
CALayer拉伸过滤
minificationFilter
:缩小图片过滤器magnificationFilter
:放大图片过滤器
// 双线性滤波算法
kCAFilterLinear
// 三线性滤波算法
kCAFilterTrilinear
// 最近过滤算法
kCAFilterNearest
kCAFilterTrilinear
和kCAFilterLinear
非常相似,大部分情况下二者都看不出来有什么差别。但是,较双线性滤波算法而言,三线性滤波算法存储了多个大小情况下的图片(也叫多重贴图),并三维取样,同时结合大图和小图的存储进而得到最后的结果kCAFilterNearest
是一种比较武断的方法。从名字不难看出,这个算法(也叫最近过滤)就是取样最近的单像素点而不管其他的颜色。这样做非常快,也不会使图片模糊。但是,最明显的效果就是,会使得压缩图片更糟,图片放大之后也显得块状或是马赛克严重
- 对于没有斜线的小图来说,最近过滤算法要好很多。总的来说,对于比较小的图或者是差异特别明显,极少斜线的大图,最近过滤算法会保留这种差异明显的特质以呈现更好的结果。但是对于大多数的图尤其是有很多斜线或是曲线轮廓的图片来说,最近过滤算法会导致更差的结果。换句话说,线性过滤保留了形状,最近过滤则保留了像素的差异
// 默认的kCAFilterLinear
view.layer.magnificationFilter = kCAFilterNearest;
CALayer的子类
进一步扩展使用Core Animation
绘图的能力。
CAShapeLayer
CATextLayer
CATransformLayer
CAGradientLayer
CAReplicatorLayer
CAScrollLayer
CATiledLayer
CAEmitterLayer
CAEAGLLayer
AVPlayerLayer