CAShapeLayer绘图

Deadly 提交于 2020-03-26 00:18:08

 

之前讲过使用UIBezierPath在UIView的drawRect中绘图, 今天我们讲下另外一种方式: CAShaperLayer

先说说使用CAShapeLayer的优点: GPU执行, GPU执行GPU执行

 

比如我们要画这样一个形状,

 

按照之前的思路是创建一个UIView子类, 用UIBezierPath画一个外围的不闭合圆弧, 在画中间点圆

代码量不是很多弹也不少, 那假如用CAShapeLayer实现时怎么样子的呢?

我们先上代码:

复制代码
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    //定义一个CAShapeLayer
    CAShapeLayer *myShapeLayer = ({
    
        //初始化一个实例对象
        CAShapeLayer *circle = [CAShapeLayer layer];
        
        circle.bounds        = CGRectMake(0, 0, 100, 100);  //设置大小
        circle.position      = self.view.center;            //设置中心位置
        circle.path          = \
        [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 100, 100)].CGPath; //设置绘制路径
        circle.strokeColor   = [UIColor redColor].CGColor;      //设置划线颜色
        circle.fillColor     = [UIColor yellowColor].CGColor;   //设置填充颜色
        circle.lineWidth     = 10;          //设置线宽
        circle.lineCap       = @"round";    //设置线头形状
        circle.strokeEnd     = 0.75;        //设置轮廓结束位置
        
        circle;
    });
    
    //以subLayer的形式添加给self.view
    [self.view.layer addSublayer:myShapeLayer];
}

@end
复制代码

 

你没看错, 就是这么简单 甚至不用创建UIView子类

我们讲下几个重要属性:

path

可以看到,这里用的是UIBezierPath生成一个path,然后取他的CGPath来获取路径的。他是什么呢?

一层对CGPath的封装,他更符合OC面向对象的语法风格。这都不是重点。重点是这里有一个初学者经常会犯的错误

同学们在绘制曲线的时候经常会以layer在父图层中的相对位置去绘制曲线,这是错的!!!

应该以layer自身的坐标系划线。别不当回事,你错的时候就知道咋回事了😈

另外,如下图所示,整个圆形UIBezierPath其实是分为多个子路径绘制的

 

strokeEnd

是轮廓终点的属性,取值范围[0,1]。代表轮廓终点在整条路径的百分比处,相应的还有strokeStart属性。

不过你应该思考的是:

首先,哪个是所谓的终点靠上的那个点是终点。那为什么0.75是在那个位置呢?请记住,在iOS中,以x轴正方向(即水平向右)为0度,顺时针旋转一周为360度。

 

下面我们再使用CAShapeLayer绘制一些特殊的形状

 

比如hud这个, 我们之前用UIBezierPath在UIView的DrawRect中画画过, 相对比较简单

我们用CAShapeLayer事实看。

思路:

一个圆角正方形 + 一个空心圆 + 里面的圆弧

上代码, 重要方法都有注解

复制代码
    
    CAShapeLayer *layer = ({
    
        CGRect rect = CGRectMake(0, 0, 100, 100);
        
        //创建矩形圆角正方形路径
        UIBezierPath * rectP   = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5];
        
        //创建圆路径
        UIBezierPath * circleP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 80, 80)];
        
        //内部弧路径
        UIBezierPath * interP  = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 50)
                                                                radius:35
                                                            startAngle:1.5 * M_PI
                                                              endAngle:1.7 * M_PI
                                                             clockwise:NO];
        [interP addLineToPoint:CGPointMake(50, 50)];
        [interP closePath];
        
        //合体
        [rectP appendPath:circleP];
        [rectP appendPath:interP];
        
        CAShapeLayer * layer = [CAShapeLayer layer];
        layer.bounds         = CGRectMake(0, 0, 100, 100);
        layer.position       = self.view.center;
        layer.path           = rectP.CGPath;
        layer.fillColor      = [UIColor colorWithWhite:0 alpha:0.5].CGColor;
        layer.fillRule       = kCAFillRuleEvenOdd;  //重点, 填充规则
        
        layer;
    });
    
    [self.view.layer addSublayer:layer];
复制代码

 

下面我们再画这样一个圆形进度条

直接上代码

复制代码
#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, assign)  CGFloat  end;
@property (nonatomic, strong)  CAShapeLayer *mylayer;
@property (nonatomic, strong)  CADisplayLink *displayLink;
@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];

    self.mylayer = ({

        //创建圆路径
        UIBezierPath * circleP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 80, 80)];
        
        
        CAShapeLayer * layer = [CAShapeLayer layer];
        layer.bounds         = CGRectMake(0, 0, 100, 100);
        layer.position       = self.view.center;
        layer.path           = circleP.CGPath;
        layer.strokeColor    = [[UIColor redColor] colorWithAlphaComponent:0.5].CGColor;
        layer.lineWidth      = 1;
        layer.strokeStart    = 0;
        layer.strokeEnd      = 0;
        layer.fillColor      = [UIColor clearColor].CGColor;
        layer.fillRule       = kCAFillRuleEvenOdd;
        
        layer;
    });
    
    [self.view.layer addSublayer:self.mylayer];
    
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeEnd)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

}

- (void)changeEnd {
    
    self.end = self.end + 0.01;
    self.mylayer.strokeEnd = self.end;
    if (self.end == 1) {
        
        [self.displayLink invalidate];
    }
}

@end
复制代码

 

我们再来看看这个动画效果

思路是在绿色的CALayer上面放一个红色的CAShapeLayer, 然后逐渐增加CAShapeLayer的填色大小

上代码:

复制代码
#import "ViewController.h"

static CGFloat count;

@interface ViewController ()

@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic, strong) CALayer       *greenLayer;
@property (nonatomic, strong) CAShapeLayer  *redLayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    self.greenLayer = ({
    
        CALayer *layer        = [CALayer layer];
        layer.bounds          = CGRectMake(0, 0, 200, 45);
        layer.position        = self.view.center;
        layer.backgroundColor = [UIColor greenColor].CGColor;
        
        layer;
    });
    
    self.redLayer = ({
    
        CAShapeLayer *layer   = [CAShapeLayer layer];
        layer.bounds          = CGRectMake(0, 0, 200, 45);
        layer.position        = self.view.center;
        layer.path            = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, count / 6 * 2, 45)].CGPath;
        layer.fillColor       = [UIColor redColor].CGColor;
        layer.fillRule        = kCAFillRuleEvenOdd;
        
        layer;
    });
    
    [self.view.layer addSublayer:self.greenLayer];
    [self.view.layer addSublayer:self.redLayer];
    
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(action)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)action {
    
    count ++;
    self.redLayer.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, count / 6 * 2, 45)].CGPath;
    
    if (count > 60 * 10 -1) {
        [self.displayLink invalidate];
    }
}
复制代码

之前讲过使用UIBezierPath在UIView的drawRect中绘图, 今天我们讲下另外一种方式: CAShaperLayer

先说说使用CAShapeLayer的优点: GPU执行, GPU执行GPU执行

 

比如我们要画这样一个形状,

 

按照之前的思路是创建一个UIView子类, 用UIBezierPath画一个外围的不闭合圆弧, 在画中间点圆

代码量不是很多弹也不少, 那假如用CAShapeLayer实现时怎么样子的呢?

我们先上代码:

复制代码
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    //定义一个CAShapeLayer
    CAShapeLayer *myShapeLayer = ({
    
        //初始化一个实例对象
        CAShapeLayer *circle = [CAShapeLayer layer];
        
        circle.bounds        = CGRectMake(0, 0, 100, 100);  //设置大小
        circle.position      = self.view.center;            //设置中心位置
        circle.path          = \
        [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 100, 100)].CGPath; //设置绘制路径
        circle.strokeColor   = [UIColor redColor].CGColor;      //设置划线颜色
        circle.fillColor     = [UIColor yellowColor].CGColor;   //设置填充颜色
        circle.lineWidth     = 10;          //设置线宽
        circle.lineCap       = @"round";    //设置线头形状
        circle.strokeEnd     = 0.75;        //设置轮廓结束位置
        
        circle;
    });
    
    //以subLayer的形式添加给self.view
    [self.view.layer addSublayer:myShapeLayer];
}

@end
复制代码

 

你没看错, 就是这么简单 甚至不用创建UIView子类

我们讲下几个重要属性:

path

可以看到,这里用的是UIBezierPath生成一个path,然后取他的CGPath来获取路径的。他是什么呢?

一层对CGPath的封装,他更符合OC面向对象的语法风格。这都不是重点。重点是这里有一个初学者经常会犯的错误

同学们在绘制曲线的时候经常会以layer在父图层中的相对位置去绘制曲线,这是错的!!!

应该以layer自身的坐标系划线。别不当回事,你错的时候就知道咋回事了😈

另外,如下图所示,整个圆形UIBezierPath其实是分为多个子路径绘制的

 

strokeEnd

是轮廓终点的属性,取值范围[0,1]。代表轮廓终点在整条路径的百分比处,相应的还有strokeStart属性。

不过你应该思考的是:

首先,哪个是所谓的终点靠上的那个点是终点。那为什么0.75是在那个位置呢?请记住,在iOS中,以x轴正方向(即水平向右)为0度,顺时针旋转一周为360度。

 

下面我们再使用CAShapeLayer绘制一些特殊的形状

 

比如hud这个, 我们之前用UIBezierPath在UIView的DrawRect中画画过, 相对比较简单

我们用CAShapeLayer事实看。

思路:

一个圆角正方形 + 一个空心圆 + 里面的圆弧

上代码, 重要方法都有注解

复制代码
    
    CAShapeLayer *layer = ({
    
        CGRect rect = CGRectMake(0, 0, 100, 100);
        
        //创建矩形圆角正方形路径
        UIBezierPath * rectP   = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:5];
        
        //创建圆路径
        UIBezierPath * circleP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 80, 80)];
        
        //内部弧路径
        UIBezierPath * interP  = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 50)
                                                                radius:35
                                                            startAngle:1.5 * M_PI
                                                              endAngle:1.7 * M_PI
                                                             clockwise:NO];
        [interP addLineToPoint:CGPointMake(50, 50)];
        [interP closePath];
        
        //合体
        [rectP appendPath:circleP];
        [rectP appendPath:interP];
        
        CAShapeLayer * layer = [CAShapeLayer layer];
        layer.bounds         = CGRectMake(0, 0, 100, 100);
        layer.position       = self.view.center;
        layer.path           = rectP.CGPath;
        layer.fillColor      = [UIColor colorWithWhite:0 alpha:0.5].CGColor;
        layer.fillRule       = kCAFillRuleEvenOdd;  //重点, 填充规则
        
        layer;
    });
    
    [self.view.layer addSublayer:layer];
复制代码

 

下面我们再画这样一个圆形进度条

直接上代码

复制代码
#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, assign)  CGFloat  end;
@property (nonatomic, strong)  CAShapeLayer *mylayer;
@property (nonatomic, strong)  CADisplayLink *displayLink;
@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];

    self.mylayer = ({

        //创建圆路径
        UIBezierPath * circleP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 80, 80)];
        
        
        CAShapeLayer * layer = [CAShapeLayer layer];
        layer.bounds         = CGRectMake(0, 0, 100, 100);
        layer.position       = self.view.center;
        layer.path           = circleP.CGPath;
        layer.strokeColor    = [[UIColor redColor] colorWithAlphaComponent:0.5].CGColor;
        layer.lineWidth      = 1;
        layer.strokeStart    = 0;
        layer.strokeEnd      = 0;
        layer.fillColor      = [UIColor clearColor].CGColor;
        layer.fillRule       = kCAFillRuleEvenOdd;
        
        layer;
    });
    
    [self.view.layer addSublayer:self.mylayer];
    
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(changeEnd)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

}

- (void)changeEnd {
    
    self.end = self.end + 0.01;
    self.mylayer.strokeEnd = self.end;
    if (self.end == 1) {
        
        [self.displayLink invalidate];
    }
}

@end
复制代码

 

我们再来看看这个动画效果

思路是在绿色的CALayer上面放一个红色的CAShapeLayer, 然后逐渐增加CAShapeLayer的填色大小

上代码:

复制代码
#import "ViewController.h"

static CGFloat count;

@interface ViewController ()

@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic, strong) CALayer       *greenLayer;
@property (nonatomic, strong) CAShapeLayer  *redLayer;

@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    self.greenLayer = ({
    
        CALayer *layer        = [CALayer layer];
        layer.bounds          = CGRectMake(0, 0, 200, 45);
        layer.position        = self.view.center;
        layer.backgroundColor = [UIColor greenColor].CGColor;
        
        layer;
    });
    
    self.redLayer = ({
    
        CAShapeLayer *layer   = [CAShapeLayer layer];
        layer.bounds          = CGRectMake(0, 0, 200, 45);
        layer.position        = self.view.center;
        layer.path            = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, count / 6 * 2, 45)].CGPath;
        layer.fillColor       = [UIColor redColor].CGColor;
        layer.fillRule        = kCAFillRuleEvenOdd;
        
        layer;
    });
    
    [self.view.layer addSublayer:self.greenLayer];
    [self.view.layer addSublayer:self.redLayer];
    
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(action)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

- (void)action {
    
    count ++;
    self.redLayer.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, count / 6 * 2, 45)].CGPath;
    
    if (count > 60 * 10 -1) {
        [self.displayLink invalidate];
    }
}
复制代码
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!