首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用CAShapeLayer绘图

使用CAShapeLayer绘图

作者头像
周希
发布2019-10-15 11:42:13
1K0
发布2019-10-15 11:42:13
举报
文章被收录于专栏:APP自动化测试APP自动化测试

之前讲过使用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];
    }
}

这个动画稍微修改下是不是就可以用作进度指示器了呢

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-01-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档