各种 CALayer 子类可以满足各种界面绘制的场景。这算是 CALayer 对外提供的工具类了,用它们可以方便地绘制你想要的图形。
绘图时要注意的点:
- 一般要设置 layer 的 contentScale = [UIScreen mainScreen].scale;
- 使用传用图层可以直接添加,无需手动调用
setNeedDisplay
方法;
1 CATextLayer
Core Animation
提供了一个 CALayer
的子类 CATextLayer
,它以图层的形式包含了 UILabel
几乎所有的绘制特性,并且额外提供了一些新的特性。让你可以方便地制作一个包含你想要文本的图层。
1.1 什么要使用 CATextLayer?
CATextLayer 相较 UILabel 要更轻量级、更快些。CATextLayer 使用 Core text 渲染,速度上更快;
1.2 主要参数
CATextLayer 主要参数1 2 3 4 5 6 7 8 9 10 11 12
| · string 要输出的字符串,这个是 CATextLayer 最主要的属性
· bounds 图层的大小,忘了设这个你的 text 就无法显示了
·font, fontSize, alignmentMode 字体,字体大小,对齐方式
· foregroundColor 字体的颜色
|
1.3 示例:
CATextLayer 使用示例1 2 3 4 5 6 7 8 9 10
| CATextLayer *tLayer =[CATextLayer layer]; tLayer.contentsScale = [UIScreen mainScreen].scale; tLayer.string = @"CATextLayer 测试一下"; tLayer.bounds = CGRectMake(0, 0, 300, 20); tLayer.fontSize = 14.f; tLayer.font = (__bridge CFTypeRef _Nullable)(@"HelveticaNeue-BoldItalic"); tLayer.alignmentMode = kCAAlignmentCenter; tLayer.position = CGPointMake(150, 0); tLayer.foregroundColor =[UIColor redColor].CGColor;
|
2 CAShapeLayer
CAShapeLayer
可以用来绘制所有能够通过 CGPath
来表示的形状。这个形状不一定要闭合,路径也不一定要不可破。
因此,CAShapeLayer
经常与 UIBezierPath
一起使用。UIBezierPath
类允许你在自定义的 View 中绘制和渲染由直线和曲线组成的路径。你可以在初始化的时候直接为你的 UIBezierPath
指定一个几何图形。
通俗点就是 UIBezierPath
用来指定绘制图形路径,而 CAShapeLayer
就是根据路径来绘图的。
使用 CAShpageLayer 同样有许多优点:
- 渲染快速。
CAShapeLayer
使用了硬件加速,绘制同一图形会比用 Core Graphics
要快很多。
- 高效使用内存。一个
CAShapeLayer
不需要像普通 CALayer
一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
- 不会出现像素化。当你给
CAShapeLayer
做 3D 变换时,它不像一个有寄宿图的普通图层一样变得像素化。
2.1 主要参数
CAShapeLayer 主要参数1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| - path 图层要绘制的路径,这个可以说是最主要的属性了。
- fillColor , strokeColor 描边色与都填充色。
- fillRule 填充规则,'non-zero' or 'even-odd'。
- stokeStart , strokeEnd 绘制描边时的区域,取值为比例位置 (like anchorPoint, 0~1,0 是开始位置,1 为结束位置)
- lineWidth , miterLimit, lineCap , lineJoin, lineDashPhase, lineDashPattern lineWidth: 线宽 miterLimit: 最大斜接长度 (与动画相关)。 lineCap: 线段头样式 (kCALineCapButt, kCALineCapRound ,kCALineCapSquare)。 lineJoin: 连接点样式 (kCALineJoinMiter、kCALineJoinRound、kCALineJoinBevel), lineDashPhase: 虚线起始位置。 lineDashPattern:虚线样式模板(数组)。
|
2.2 示例
使用 CAShapeLayer 在黄色区域中画一个矩形1 2 3 4 5 6 7 8 9 10 11 12 13 14
| CAShapeLayer *sLayer = [CAShapeLayer layer]; sLayer.contentsScale = [UIScreen mainScreen].scale; sLayer.frame = CGRectMake(0, 0, 150, 150); sLayer.backgroundColor = [UIColor yellowColor].CGColor; sLayer.strokeColor = [UIColor blueColor].CGColor; sLayer.fillColor = [UIColor redColor].CGColor; sLayer.lineJoin = kCALineJoinRound; sLayer.lineCap = kCALineCapRound; sLayer.lineWidth = 4; UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(10, 10, 100, 100) byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(10, 10)]; sLayer.path = path.CGPath;
|
如果我们想像 Transform 那章 一样画了多个立方形,怎么去旋转他们呢?
在那一章中,我们是通过转动父 layer 的 sublayerTransform
属性来实现的,但是如果是多个立方形,就不能这样的,不然多个立方形会跟着一起转动。
那我们怎么做呢?我们可以创建一个 CATransformLayer
,然后把每个立方形放到独立的 CATransformLayer
上,当要转动时,直接转动 CATransformLayer
就行了,他会对其中的子 layer 一起转动(只需要赋值给其 transform 属性),相当于 sublayerTransform
.
1 2 3 4 5 6
| CATransformLayer *cube = [CATransformLayer layer];
[cube addSublayer:face1]; ...
... cube.transform = transform;
|
4 CAGradientLayer
渐变色图层控件,可以很方便地画出渐变色控件。
4.1 主要参数
1 2 3 4 5 6 7 8 9 10 11 12 13
| - colors : array<id CGColor> 传入一个数组,规定所有的渐变色。
- locations : array<NSNumber> 渐变颜色的区间分布(就是 colos 中每个渐变颜色的起点和最后颜色的终点位置,这里用的是比例位置,参考 anchorPoint),locations 的数组长度和 colors 一致。这个属性可不设,默认是 nil,系统会平均分布颜色如果有特定需要可设置,数组设置为 0 ~ 1 之间单调递增。
- startPoint , endPoint 使用与 anchorPoint 一样的比例坐标,startPoint 默认 (0.5, 0), endPoint 默认 (0.5,1),也就是从顶边的中点,到底边的中点,从上到下渐变。
- type 绘制类型,默认 kCAGradientLayerAxial(表示按像素均匀变化)。
|
4.2 示例
画一个渐变的矩形1 2 3 4 5 6 7 8 9
| CAGradientLayer *gLayer = [CAGradientLayer new]; gLayer.contentsScale = [UIScreen mainScreen].scale; gLayer.frame = CGRectMake(0, 0, 100, 100); gLayer.colors = @[(id)[UIColor blueColor].CGColor, (id)[UIColor redColor].CGColor]; gLayer.type = kCAGradientLayerAxial; gLayer.locations = @[@0.0f, @1.0f]; layerFrame = [UIView new]; [layerFrame.layer addSublayer:gLayer]; layerFrame.flexSize = CGSizeMake(100, 100);
|
5 CAReplicatorLayer
CAReplicatorLayer
的功能是用于高效地生成许多相似的图层。
5.1 主要属性
CAReplicatorLayer 主要属性1 2 3 4 5 6 7
| · instanceCount 指定图层要重复的次数
· instanceTransform 指定一个 CATransform3D 变换,变换是逐步增加的,每个实例都是相对于前一个实现的变换!(这就是为什么最终复制体会出现在不同位置的原因)
|
5.2 示例 - 由重复小方块组成的圆圈
示例效果可以在我的 iOSOneDemo 中查看。
由重复小方块组成的圆圈1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| - (void)addReplicatorLayerOfView:(UIView *)view { CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer]; replicatorLayer.frame = CGRectMake(0, 0, 300, 300); [view.layer addSublayer:replicatorLayer];
replicatorLayer.instanceCount = 10;
CATransform3D transform = CATransform3DIdentity; transform = CATransform3DRotate(transform, M_PI / 5.0, 0, 0, 1); replicatorLayer.instanceTransform = transform;
replicatorLayer.instanceBlueOffset = -0.1; replicatorLayer.instanceGreenOffset = -0.1;
CALayer *cube = [CALayer layer]; cube.bounds = CGRectMake(0, 0, 20, 20); cube.position = CGPointMake(150, 20); cube.backgroundColor = [UIColor whiteColor].CGColor; [replicatorLayer addSublayer:cube]; }
|
5.3 示例 2 - 一个水纹动画
下面这个示例可能需要一些动画的基础,可以参考相关 iOS 动画的章节。
一个水纹动画1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| - (void)addWaveAnimationInView:(UIView *)view { CAShapeLayer *animLayer = [CAShapeLayer layer]; animLayer.contentsScale = [UIScreen mainScreen].scale; animLayer.position = CGPointMake(150, 150); animLayer.bounds = CGRectMake(0, 0, 100, 100); animLayer.backgroundColor = [UIColor clearColor].CGColor; animLayer.fillColor = [UIColor greenColor].CGColor; UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:animLayer.bounds]; animLayer.path = path.CGPath; animLayer.transform = CATransform3DMakeScale(0, 0, 1); CABasicAnimation *sizeAnim = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; sizeAnim.fromValue = @0; sizeAnim.toValue = @1; [animLayer addAnimation:sizeAnim forKey:nil]; CABasicAnimation *alphaAnim = [CABasicAnimation animationWithKeyPath:@"opacity"]; alphaAnim.fromValue = @1; alphaAnim.toValue = @0; CAAnimationGroup *animGroup = [CAAnimationGroup animation]; animGroup.animations = @[sizeAnim, alphaAnim]; animGroup.duration = 2; animGroup.repeatCount = HUGE; [animLayer addAnimation:animGroup forKey:nil];
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer]; replicatorLayer.frame = CGRectMake(0, 0, 300, 300); [view.layer addSublayer:replicatorLayer]; replicatorLayer.instanceCount = 5; replicatorLayer.instanceDelay = 0.4; [replicatorLayer addSublayer:animLayer]; }
|
6 引用
【1】[Matt Neuburg - 《Programming iOS deep into views,view controllers and frameworks》]
【2】[Nick LockWood - 《iOS Core Animation: Advanced Techniques》]