一:CATiledLayer
继承自CALayer,它能够实现异步的分区的绘制,并且只绘制屏幕显示的范围,在特定的场景下非常好用.使用也很简单
//在自定义View中重写layerClass
+(Class)layerClass{
return [CATiledLayer class];
}
//在init中设置layer的属性
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
tiledLayer.levelsOfDetail = 1;
tiledLayer.levelsOfDetailBias = ceil(log2(1/scale))+1;
tiledLayer.tileSize = CGSizeMake(50, 50);
levelsOfDetail和levelsOfDetailBias是关于图片和layer尺寸之间的关系,假设图片铺满layer,假设一开始layer是100x100,那么在retina屏上最多就是300x300个像素,去显示一个10000x10000的位图时,会舍弃大部分的像素,这时将layer放大到300x300,如果不重绘就仍然是那些像素,就会模糊
levelsOfDetailBias是layer放大时,图片放大的次数,每增加1,就放大一倍,也就是平方.重绘时需要根据layer的rect来设置.
levelsOfDetail是layer缩小时,达到重绘的节点,设置为1,那么缩小layer就不会引起重绘;
详细的介绍

二:CAGradientLayer
CAGradientLayer实现了渐变色功能,是CALayer子类,使用非常简单快捷,但是它和Core Graphics的一系列渐变色API应该是没有关系的,因为CALayer在Core Animation框架内
CAGradientLayer *gl = [CAGradientLayer layer];
gl.startPoint = CGPointMake(0, 0);
gl.endPoint = CGPointMake(1, 1);
gl.colors = @[(__bridge id)UIColor.blackColor.CGColor,(__bridge id)[UIColor.blackColor colorWithAlphaComponent:.5].CGColor,(__bridge id)[UIColor.blackColor colorWithAlphaComponent:.0].CGColor];
gl.locations = @[@0.25,@.75,@1.0];
gl.bounds = layer.bounds;
gl.anchorPoint = CGPointMake(0, 0);
gl.position = CGPointMake(0, 0);
//gl.type = kCAGradientLayerRadial;
[layer addSublayer:gl];
1.这里直接创建了一个CAGradientLayer,渐变一般创建出来使用比较多,当然也可以重写+ (Class)layerClass来作为root layer
2.colors提供渐变的几个节点颜色,这里使用黑色的不同透明度
3.locations提供每个节点在什么位置开始生效
4.startPoint和endPoint提供渐变的起始和结束点,并不是真正的点,是类似锚点,取值在0-1,这两个参数决定了渐变产生的方向,两点连成的线是垂直于渐变的rgba等值线

5.type默认是kCAGradientLayerAxial,rgba等值线是直线,kCAGradientLayerRadial的rgba等值线是锥形,kCAGradientLayerConic是带有弧度的,依据(0,0)startpoint和(0,0)endpoint两个向量去做弧形渐变,只能在iOS12以上使用,

三: CAShapeLayer
CAShapeLayer实现了绘图的功能,它的核心就是给CGPath一个容器,使用时最关键的内容就是构建CGPath
CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,它是矢量图形,而不是bitmap,所以无论有多大,都不会占用太多的内存。
CAShapeLayer可以在边界之外绘制,图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉.
CAShapeLayer *sl = [CAShapeLayer layer];
sl.path = CGPathCreateWithRoundedRect(CGRectMake(50, 50, 100, 100), 15, 15, nil);
sl.strokeColor = UIColor.redColor.CGColor;
sl.fillColor = UIColor.clearColor.CGColor;
sl.lineWidth = 5;
[self.view.layer addSublayer:sl];

只要是CGPath就行,当然用UIBezierPath构建路径也可以.
三: CATextLayer
看名字就知道是用来显示文本的,CATextLayer使用了Core text,它的性能比UILabel更强,当需要绘制大量文字的时候,可以选择使用CATextLayer,比如文章,电子书.
NSString *str = @"CATextLayer disables sub-pixel antialiasing when rendering text. Text can only be drawn using sub-pixel antialiasing when it is composited into an existing opaque background at the same time that it's rasterized. There is no way to draw text with sub-pixel antialiasing by itself, whether into an image or a layer, in advance of having the background pixels to weave the text pixels into. Setting the opacity property of the layer to YES does not change the rendering mode.";
CATextLayer *tl = [CATextLayer layer];
tl.frame = CGRectMake(20, 100, 400, 400);
[self.view.layer addSublayer:tl];
tl.contentsScale = UIScreen.mainScreen.scale;
tl.wrapped = YES;
tl.alignmentMode = kCAAlignmentLeft;
tl.foregroundColor = UIColor.orangeColor.CGColor;
UIFont *font = [UIFont systemFontOfSize:16];
CFStringRef fontName = (__bridge CFStringRef)font.fontName;
CGFontRef fontref = CGFontCreateWithFontName(fontName);
tl.font = fontref;
tl.fontSize = font.pointSize;
CGFontRelease(fontref);
NSMutableAttributedString *att = [[NSMutableAttributedString alloc]initWithString:str];
NSMutableParagraphStyle *ps = [NSMutableParagraphStyle new];
ps.lineSpacing = 5;
[att addAttributes:@{NSParagraphStyleAttributeName : ps,NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:UIColor.orangeColor} range:NSMakeRange(0, att.length)];
// tl.string = att;
tl.string = str;
1.contentsScale是物理像素和逻辑point的关系,也就是1x2x3x
2.wrapped是换行
3.alignmentMode是布局模式,对标UIlalbel的textAlignment
4.foregroundColor是字体颜色
5.CATextLayer的font需要的是CGFontRef
6.string是id类型,可以是NSString也可以是NSAttributedString,当使用NSString时,上面的45,也就是颜色和font两个属性才会生效,使用NSAttributedString的时候颜色和font只会从富文本的Attributes中取,如果没有则是黑色和默认字体大小.
四: CALayer的子类结合mask
写一个渐变文本的例子
CATextLayer *tl = [CATextLayer layer];
tl.contentsScale = UIScreen.mainScreen.scale;
tl.wrapped = YES;
tl.alignmentMode = kCAAlignmentLeft;
tl.foregroundColor = UIColor.orangeColor.CGColor;
NSMutableAttributedString *att = [[NSMutableAttributedString alloc]initWithString:str];
NSMutableParagraphStyle *ps = [NSMutableParagraphStyle new];
ps.lineSpacing = 5;
[att addAttributes:@{NSParagraphStyleAttributeName : ps,NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:UIColor.orangeColor} range:NSMakeRange(0, att.length)];
tl.string = att;
CAGradientLayer *gl = [CAGradientLayer layer];
gl.startPoint = CGPointMake(0, 0);
gl.endPoint = CGPointMake(1, 1);
gl.colors = @[(__bridge id)UIColor.redColor.CGColor,(__bridge id)UIColor.orangeColor.CGColor,(__bridge id)UIColor.yellowColor.CGColor];
gl.locations = @[@0.2,@.6,@1.0];
gl.type = kCAGradientLayerAxial;
tl.frame = CGRectMake(0, 0, ScreenWidth-40, 400);
gl.frame = (CGRect){20,100,tl.frame.size};
[gl setMask:tl];
[self.view.layer addSublayer:gl];
gl是一个渐变的色块,被添加到界面上,这时候给gl添加一个mask,mask的显示原则是alpha通道过滤,在mask完全透明的位置,对应gl的部分则完全不可见,mask完全不透明的部分,对应gl的部分则正常显示,这个例子mask是CATextLayer,其中文字是完全不透明的,非文字的区域是透明的,最终效果就是渐变层被纹上了文字一般,而且文字颜色是渐变层自己的颜色.
需要注意gl和tl的frame,或者设置anchorPoint和position,mask需要完全贴合layer,所以tl的origin是0,0,size和gl一样

五:CAReplicatorLayer
CAReplicatorLayer可以copy已有的layer,形成一组重复的layer,并且可以定义这一组layer的变换规律,甚至可以借此制作动画效果
1.实现镜像效果
+ (Class)layerClass{
return CAReplicatorLayer.class;
}
- (instancetype)initWithFrame:(CGRect)frame{
if(self = [super initWithFrame:frame]){
CAReplicatorLayer *layer = (CAReplicatorLayer *)self.layer;
layer.instanceCount = 2;
CATransform3D transform = CATransform3DIdentity;
CGFloat verticalOffset = self.bounds.size.height + 2;
transform = CATransform3DTranslate(transform, 0, verticalOffset, 0);
transform = CATransform3DScale(transform, 1, -1, 0);
layer.instanceTransform = transform;
layer.instanceAlphaOffset = -0.6;
}
return self;
}
TestView *tv = [[TestView alloc]initWithFrame:CGRectMake(100, 100, 200, 200)];
[self.view addSubview:tv];
_imgv = UIImageView.new;
_imgv.image = [UIImage imageNamed:@"avatar"];
_imgv.frame = CGRectMake(0, 0, 200, 200);
[tv addSubview:_imgv];
自定义了一个TestView,在构造方法中设置CAReplicatorLayer的属性
instanceCount是重复个数
instanceTransform是变换效果
instanceAlphaOffset是透明度

被复制的layer并不是真正的layer,只是绘制效果(图形),最终只有一个layer,第二个图形根据第一个图形,按照instanceTransform进行变换,第三个图形会在第二个的基础上进行变换
改造一下上面的代码再看看
CAReplicatorLayer *layer = (CAReplicatorLayer *)self.layer;
layer.instanceCount = 3;
CATransform3D transform = CATransform3DIdentity;
CGFloat verticalOffset = self.bounds.size.height + 2;
transform = CATransform3DTranslate(transform, 0, verticalOffset, 0);
// transform = CATransform3DScale(transform, 1, -1, 0);
transform = CATransform3DRotate(transform, M_PI_4, 0, 0, 1);
layer.instanceTransform = transform;
layer.instanceAlphaOffset = -0.2;

可以看到,第二张旋转了45度,但是第三张在第二张的基础上旋转,因此被旋转了90度.
2.制作动画
CAReplicatorLayer *layer = (CAReplicatorLayer *)self.layer;
layer.instanceCount = 10;
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DRotate(transform, M_PI/5, 0, 0, 1);
layer.instanceTransform = transform;
layer.instanceAlphaOffset = -0.05;
layer.instanceDelay = .15;
TestView *tv = [[TestView alloc]initWithFrame:CGRectMake(0, 100, 414, 414)];
[self.view addSubview:tv];
_imgv = UIImageView.new;
_imgv.image = [UIImage imageNamed:@"avatar"];
_imgv.frame = CGRectMake(190, 0, 34, 34);
[tv addSubview:_imgv];
改造一下刚才的代码,copy10次,每个都比上一个多旋转36度,在testView上add一张图,放在上面的位置,_imgv.frame = CGRectMake(190, 0, 34, 34);每当copy并旋转一次,就多一个image,这里需要注意的是,instanceTransform是写在TestView里的,也就是说,旋转的是TestView的layer本身,而不是image,所以最终形成表盘一样的效果.

接下来给image添加一个动画
_imgv.transform = CGAffineTransformScale(CGAffineTransformIdentity, .1, .1);
CABasicAnimation *an2 = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
an2.fromValue = @(1.0);
an2.toValue = @(0.1);
an2.cumulative = YES;
an2.repeatCount = CGFLOAT_MAX;
an2.duration = 1.5;
an2.fillMode = kCAFillModeForwards;
an2.removedOnCompletion = NO;
[_imgv.layer addAnimation:an2 forKey:@"an2"];
在添加动画之前,先修改_imgv的大小,改成最小状态,看起来更舒服
只是这样的话,10个小图片会同时动画,CAReplicatorLayer还提供了一个很强的属性,instanceDelay,它可以使被copy的图形按照延迟来执行动画,和instanceTransform,instanceAlphaOffset一样都是递增的.

网友评论