CAShapeLayer类解析(二) —— 基本使用

版本记录

版本号 时间
V1.0 2018.01.17

前言

CAShapeLayer类是我们经常用到的类,平时也就用一下其基本用法,但是很少详细的翻出来它的开发文档仔细研究下,下面,我就带领大家详细的研究下这个类,详细的看一下它的用法。感兴趣的可以看上面写的几篇。
1. CAShapeLayer类解析(一) —— 基本概览

CAShapeLayer使用

其实关于CAShapeLayer的使用,如果认真看其API文档的话,无非就是一些属性的基本使用,因为该类是没有方法暴露出来的,都是属性,下面我们讲述其基本用法也是基本围绕其属性和相关效果的演示为主。

1. @property(nullable) CGPathRef path;

定义要渲染的形状的路径。 如果路径延伸到图层边界之外,不会自动被图层剪切,则只有在正常的图层遮罩规则才会实现自动剪切。 分配后,路径被复制。 缺省为nil,可动画。 (请注意,虽然path属性是可动画的,但是当属性改变时,不会创建隐式动画。)

下面我们看一个简单示例。

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) CAShapeLayer *newlayer;

@end

@implementation ViewController

#pragma mark -  Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self initUI];
}

#pragma mark -  Object Private Function

- (void)initUI
{
    [self drawRoundView:CGPointMake(200.0, 300.0) withStartAngle:0 withEndAngle:M_PI * 2 withRadius:100.0];
}

- (void)drawRoundView:(CGPoint)centerPoint withStartAngle:(CGFloat)startAngle withEndAngle:(CGFloat)endAngle withRadius:(CGFloat)radius
{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:centerPoint radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    self.newlayer = [CAShapeLayer layer];
    self.newlayer.path = path.CGPath;
    self.newlayer.strokeColor = [UIColor blueColor].CGColor;
    self.newlayer.fillColor = [UIColor clearColor].CGColor;
    self.newlayer.lineWidth = 2;
    self.newlayer.frame = self.view.bounds;
    [self.view.layer addSublayer:self.newlayer];
    
    //动画显示圆则调用
    [self drawLineAnimation:self.newlayer];
}

- (void)drawLineAnimation:(CALayer*)layer
{
    CABasicAnimation *bas = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    bas.duration = 3;
    bas.fromValue = [NSNumber numberWithInteger:0];
    bas.toValue = [NSNumber numberWithInteger:1];
    [layer addAnimation:bas forKey:@"key"];
}

@end

下面看一下效果图

这里路径是可以随意更换的,比如我们换成一个直线

    UIBezierPath *path = [UIBezierPath bezierPath];
//    [path addArcWithCenter:centerPoint radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    [path moveToPoint:CGPointMake(200.0, 200.0)];
    [path addLineToPoint:CGPointMake(200.0, 500.0)];

然后看一下效果图

你可以切换成你任何感兴趣的路径,具体可以参考类UIBezierPath,后面我也会详细的讲述这个类的使用。

2. @property(nullable) CGColorRef fillColor;

填充路径的颜色,或无填充时为nil。 默认为不透明的黑色,可动画。

其实对于上面的例子,如果我不添加这句代码

self.newlayer.fillColor = [UIColor clearColor].CGColor;

那么效果就是这样的

这也证实了填充颜色是有默认值的,那就是黑色的,只有给clearColor才没有填充的效果。

下面我们就动画一个这个fillColor属性,下面看一下代码

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) CAShapeLayer *newlayer;

@end

@implementation ViewController

#pragma mark -  Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self initUI];
}

#pragma mark -  Object Private Function

- (void)initUI
{
    [self drawRoundView:CGPointMake(200.0, 300.0) withStartAngle:0 withEndAngle:M_PI * 2 withRadius:100.0];
}

- (void)drawRoundView:(CGPoint)centerPoint withStartAngle:(CGFloat)startAngle withEndAngle:(CGFloat)endAngle withRadius:(CGFloat)radius
{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:centerPoint radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    self.newlayer = [CAShapeLayer layer];
    self.newlayer.path = path.CGPath;
    self.newlayer.strokeColor = [UIColor blueColor].CGColor;
    self.newlayer.lineWidth = 2;
    self.newlayer.frame = self.view.bounds;
    [self.view.layer addSublayer:self.newlayer];
    
    //动画显示圆则调用
    [self drawLineAnimation:self.newlayer];
}

- (void)drawLineAnimation:(CALayer*)layer
{
    CABasicAnimation *bas = [CABasicAnimation animationWithKeyPath:@"fillColor"];
    bas.duration = 3;
    bas.fromValue = (__bridge id)[UIColor redColor].CGColor;
    bas.toValue = (__bridge id)[UIColor greenColor].CGColor;
    [layer addAnimation:bas forKey:@"key"];
}

@end

下面我们就看一下动画效果

大家可以发现,是可以实现由红色到绿色填充的动画,但是动画结束后,又回到了默认填充颜色 - 黑色。

3. @property(nullable) CGColorRef strokeColor;

这个属性用于设置描边的颜色,如果不需要描边就传nil,默认就是nil,该属性还是可动画的。

下面我们看一下,描边的效果。

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) CAShapeLayer *newlayer;

@end

@implementation ViewController

#pragma mark -  Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self initUI];
}

#pragma mark -  Object Private Function

- (void)initUI
{
    [self drawRoundView:CGPointMake(200.0, 300.0) withStartAngle:0 withEndAngle:M_PI * 2 withRadius:100.0];
}

- (void)drawRoundView:(CGPoint)centerPoint withStartAngle:(CGFloat)startAngle withEndAngle:(CGFloat)endAngle withRadius:(CGFloat)radius
{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:centerPoint radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    self.newlayer = [CAShapeLayer layer];
    self.newlayer.path = path.CGPath;
    self.newlayer.strokeColor = [UIColor blueColor].CGColor;
    self.newlayer.fillColor = [UIColor clearColor].CGColor;
    self.newlayer.lineWidth = 2;
    self.newlayer.frame = self.view.bounds;
    [self.view.layer addSublayer:self.newlayer]; 
}

@end

下面看一下效果

下面我们在动画一个这个属性,还是先看代码。

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) CAShapeLayer *newlayer;

@end

@implementation ViewController

#pragma mark -  Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self initUI];
}

#pragma mark -  Object Private Function

- (void)initUI
{
    [self drawRoundView:CGPointMake(200.0, 300.0) withStartAngle:0 withEndAngle:M_PI * 2 withRadius:100.0];
}

- (void)drawRoundView:(CGPoint)centerPoint withStartAngle:(CGFloat)startAngle withEndAngle:(CGFloat)endAngle withRadius:(CGFloat)radius
{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:centerPoint radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    self.newlayer = [CAShapeLayer layer];
    self.newlayer.path = path.CGPath;
    self.newlayer.strokeColor = [UIColor blueColor].CGColor;
    self.newlayer.fillColor = [UIColor clearColor].CGColor;
    self.newlayer.lineWidth = 2;
    self.newlayer.frame = self.view.bounds;
    [self.view.layer addSublayer:self.newlayer];
    
    //动画显示圆则调用
    [self drawLineAnimation:self.newlayer];
}

- (void)drawLineAnimation:(CALayer*)layer
{
    CABasicAnimation *bas = [CABasicAnimation animationWithKeyPath:@"strokeColor"];
    bas.duration = 3;
    bas.fromValue = (__bridge id)[UIColor redColor].CGColor;
    bas.toValue = (__bridge id)[UIColor greenColor].CGColor;
    [layer addAnimation:bas forKey:@"key"];
}

@end

下面看一下实现效果。

还是从红色变成绿色,再到蓝色这样的动画效果。

4. @property CGFloat strokeStart;和@property CGFloat strokeEnd;

这些值定义了用于绘制描边轮廓的路径的子区域。 值必须在[0,1]的范围内,其中0表示路径的开始,1表示结束。 介于0和1之间的值沿路径长度线性插值。strokeStart默认为零,strokeEnd默认为1。 两者都是可以动画的。

下面我们就动画下strokeEnd这个属性,还是先看代码。

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) CAShapeLayer *newlayer;

@end

@implementation ViewController

#pragma mark -  Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self initUI];
}

#pragma mark -  Object Private Function

- (void)initUI
{
    [self drawRoundView:CGPointMake(200.0, 300.0) withStartAngle:0 withEndAngle:M_PI * 2 withRadius:100.0];
}

- (void)drawRoundView:(CGPoint)centerPoint withStartAngle:(CGFloat)startAngle withEndAngle:(CGFloat)endAngle withRadius:(CGFloat)radius
{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:centerPoint radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    self.newlayer = [CAShapeLayer layer];
    self.newlayer.path = path.CGPath;
    self.newlayer.strokeColor = [UIColor blueColor].CGColor;
    self.newlayer.fillColor = [UIColor clearColor].CGColor;
    self.newlayer.lineWidth = 2;
    self.newlayer.strokeStart = 0.1;
    self.newlayer.frame = self.view.bounds;
    [self.view.layer addSublayer:self.newlayer];
    
    //动画显示圆则调用
    [self drawLineAnimation:self.newlayer];
}

- (void)drawLineAnimation:(CALayer*)layer
{
    CABasicAnimation *bas = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    bas.duration = 3;
    bas.fromValue = @0.1;
    bas.toValue = @0.9;
    [layer addAnimation:bas forKey:@"key"];
}

@end

下面我们就看一下效果

这个strokeEnd就自动从0.1变化到0.9。

5. @property CGFloat lineWidth;

描边操作的线宽,默认为1,可动画,下面我们就看一下动画效果,先看代码。

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) CAShapeLayer *newlayer;

@end

@implementation ViewController

#pragma mark -  Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self initUI];
}

#pragma mark -  Object Private Function

- (void)initUI
{
    [self drawRoundView:CGPointMake(200.0, 300.0) withStartAngle:0 withEndAngle:M_PI * 2 withRadius:100.0];
}

- (void)drawRoundView:(CGPoint)centerPoint withStartAngle:(CGFloat)startAngle withEndAngle:(CGFloat)endAngle withRadius:(CGFloat)radius
{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:centerPoint radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    self.newlayer = [CAShapeLayer layer];
    self.newlayer.path = path.CGPath;
    self.newlayer.strokeColor = [UIColor blueColor].CGColor;
    self.newlayer.fillColor = [UIColor clearColor].CGColor;
    self.newlayer.lineWidth = 2;
    self.newlayer.strokeStart = 0.1;
    self.newlayer.frame = self.view.bounds;
    [self.view.layer addSublayer:self.newlayer];
    
    //动画显示圆则调用
    [self drawLineAnimation:self.newlayer];
}

- (void)drawLineAnimation:(CALayer*)layer
{
    CABasicAnimation *bas = [CABasicAnimation animationWithKeyPath:@"lineWidth"];
    bas.duration = 3;
    bas.fromValue = @3;
    bas.toValue = @10;
    [layer addAnimation:bas forKey:@"key"];
}

@end

下面看一下实现效果

这就实现了宽度的动画效果。

6. @property CGFloat miterLimit;

绘制路径时使用的斜接限制, 默认为10,可动画。

斜接长度指的是在两条线交汇处内角和外角之间的距离。如下图所示。

只有lineJoin属性为kCALineJoinMiter时miterLimit才有效,边角的角度越小,斜接长度就会越大。

为了避免斜接长度过长,我们可以使用 miterLimit 属性。如果斜接长度超过 miterLimit 的值,边角会以 lineJoin的 "bevel"即kCALineJoinBevel类型来显示。

7. @property(copy) NSString *lineCap;

绘制路径时使用的帽样式。 选项是miter, roundbevel。 默认为butt

下面看一下这三个值。

/* `lineCap' values. */

CA_EXTERN NSString *const kCALineCapButt
    CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0);
CA_EXTERN NSString *const kCALineCapRound
    CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0);
CA_EXTERN NSString *const kCALineCapSquare
    CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0);

那这个属性表示什么呢?下面我们就看一下。

8. @property(copy) NSString *lineJoin;

绘制路径时使用的连接样式,选项有miter, roundbevel,默认是miter。下面看一下这几个值。

/* `lineJoin' values. */

CA_EXTERN NSString *const kCALineJoinMiter
    CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0);
CA_EXTERN NSString *const kCALineJoinRound
    CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0);
CA_EXTERN NSString *const kCALineJoinBevel
    CA_AVAILABLE_STARTING (10.6, 3.0, 9.0, 2.0);

9. @property(nullable, copy) NSArray<NSNumber *> *lineDashPattern;

设置边线的样式,默认为实线,该数组为一个NSNumber数组,数组中的数值依次表示虚线中单个线的长度,和空白的长度,如:数组@[2,2,3,4] 表示 有长度为2的线,长度为2的空白,长度为3的线,长度为4的空白,不断循环后组成的虚线。如图:

默认为nil。

10. @property CGFloat lineDashPhase;

边线样式的起始位置,即,如果lineDashPattern设置为@[@2, @2, @3, @4],lineDashPhase即为第一个长度为2的线的起始位置,默认值为0,可动画。

下面我们看一下代码。

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) CAShapeLayer *newlayer;

@end

@implementation ViewController

#pragma mark -  Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self initUI];
}

#pragma mark -  Object Private Function

- (void)initUI
{
    [self drawRoundView:CGPointMake(200.0, 300.0) withStartAngle:0 withEndAngle:M_PI * 2 withRadius:100.0];
}

- (void)drawRoundView:(CGPoint)centerPoint withStartAngle:(CGFloat)startAngle withEndAngle:(CGFloat)endAngle withRadius:(CGFloat)radius
{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:centerPoint radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
    self.newlayer = [CAShapeLayer layer];
    self.newlayer.path = path.CGPath;
    self.newlayer.strokeColor = [UIColor blueColor].CGColor;
    self.newlayer.fillColor = [UIColor clearColor].CGColor;
    self.newlayer.lineWidth = 2;
    self.newlayer.frame = self.view.bounds;
    self.newlayer.lineDashPattern = @[@2, @3, @4, @5];
    self.newlayer.lineDashPhase = 1;
    [self.view.layer addSublayer:self.newlayer];
}

@end

下面看一下实现效果。

可以看见实现的线长和间隔。

后记

这一篇结束了,相关的还会继续更新~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容