CAShapeLayer 的简单介绍

字数 1179阅读 2055

支持原创,原文地址:www.KentonYu.com

CAShapeLayer



CAShapeLayer 是一个通过矢量图形而不是 bitmap 来绘制的图层子类。可以指定颜色、线宽等属性,用CGPath 来定义想要绘制的图形,最后 CAShapeLayer 就会自动渲染出来了。当然,你也可以用 Core Graphics 直接向原始的 CALyer 的内容中绘制一个路径(<code>- drawLayer: inContext:</code>),相比之下,使用 CAShapeLayer 有以下一些优点:

  • 渲染快速。CAShapeLayer 使用了硬件加速,绘制同一图形会比用 Core Graphics 快很多。
  • 高效使用内存。一个 CAShapeLayer 不需要像普通 CALayer 一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
  • 不会被图层边界剪裁掉。一个 CAShapeLayer 可以在边界之外绘制。你的图层路径不会像在使用 Core Graphics 的普通 CALayer 一样被剪裁掉.
  • 不会出现像素化。当你给 CAShapeLayer 做 3D 变换时,它不像一个有寄宿图的普通图层一样变得像素化。


主要属性


<pre>
// CAShapeLayer 绘制的路径
@property(nullable) CGPathRef path;

//路径中的填充颜色
@property(nullable) CGColorRef fillColor;

//填充规则
@property(copy) NSString *fillRule;

//画笔颜色(路径的颜色,边框颜色)
@property(nullable) CGColorRef strokeColor;

//这是一组范围值,路径绘制开始和结束的范围(0 -> 1)
@property CGFloat strokeStart;
@property CGFloat strokeEnd;

//设置虚线显示的起点距离,设置为8,则显示长度8之后的线
@property CGFloat lineDashPhase;
//设置虚线线段的长度和空格的长度,@[@20,@30,@40,@50],画20空30画40空50
@property(nullable, copy) NSArray<NSNumber *> *lineDashPattern;

//以下属性参见 UIBezierPath 的介绍
@property CGFloat lineWidth;
@property CGFloat miterLimit;
@property(copy) NSString *lineCap;
@property(copy) NSString *lineJoin;

</pre>


Show You Code


先上本 Demo 截图。

效果图

1.使用 CAShapeLayer 绘制一个圆角矩形:

<pre>

pragma mark Getter

  • (UIBezierPath *)path {
    if (!_path) {
    _path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 100.f, CGRectGetWidth([UIScreen mainScreen].bounds), 44.f) cornerRadius:22.f];
    }
    return _path;
    }

  • (CAShapeLayer *)shapeLayer {
    if (!_shapeLayer) {
    _shapeLayer = ({
    CAShapeLayer *layer = [[CAShapeLayer alloc] init];
    layer.path = self.path.CGPath;
    layer.lineWidth = 2.f;
    layer.strokeColor = [UIColor greenColor].CGColor;
    layer.fillColor = [UIColor redColor].CGColor;
    // strokeStart 绘制起点 strokeEnd 绘制终点 取值是 0-1
    layer.strokeStart = 0;
    layer.strokeEnd = 0.7f;
    layer;
    });
    }
    return _shapeLayer;
    }
    </pre>

2.绘制一根不同间隔,不同长度的虚线

<pre>

pragma mark Getter

  • (UIBezierPath *)dashLinePath {
    if (!_dashLinePath) {
    _dashLinePath = ({
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(20.f, 180.f)];
    [path addLineToPoint:CGPointMake(CGRectGetWidth(self.frame) - 20.f, 180.f)];
    path;
    });
    }
    return _dashLinePath;
    }

  • (CAShapeLayer *)dashLineShapeLayer {
    if (!_dashLineShapeLayer) {
    _dashLineShapeLayer = ({
    CAShapeLayer *layer = [[CAShapeLayer alloc] init];
    layer.path = self.dashLinePath.CGPath;
    layer.lineDashPhase = 8;
    layer.lineDashPattern = @[@10, @20, @30, @60];
    layer.strokeColor = [UIColor greenColor].CGColor;
    layer.lineWidth = 2.f;
    layer;
    });
    }
    return _dashLineShapeLayer;
    }
    </pre>

lineDashPhase:绘制的虚线显示在屏幕上的起点,比如设置为10,则从整条线的 10 的位置开始才显示。
lineDashPattern:绘制虚线的格式,@[@10, @20, @30, @60],画10个点的线空20个点,以此类推。如果只设置一个元素,则线和间隔宽度相等。

3.使用 fillRule 属性,实现两个区域的取非

<pre>

pragma mark Getter

  • (UIBezierPath )fillRulePath {
    if (!_fillRulePath) {
    //这里先绘制哪个 Path 效果一样
    _fillRulePath = [UIBezierPath bezierPathWithRect:CGRectMake(20.f, 200.f, CGRectGetWidth(self.frame)-40.f, 200.f)];
    [_fillRulePath appendPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetWidth(self.frame)/2.f, 300.f) radius:50.f startAngle:0 endAngle:2
    M_PI clockwise:NO]];
    }
    return _fillRulePath;
    }

  • (CAShapeLayer *)fillRuleShapeLayer {
    if (!_fillRuleShapeLayer) {
    _fillRuleShapeLayer = ({
    CAShapeLayer *layer = [[CAShapeLayer alloc] init];
    layer.path = self.fillRulePath.CGPath;
    layer.fillRule = kCAFillRuleEvenOdd;
    layer.fillColor = [UIColor yellowColor].CGColor;
    layer;
    });
    }
    return _fillRuleShapeLayer;
    }

</pre>

填充规则介绍:

kCAFillRuleNonZero:默认值,非零规则,当这个点作任意方法的射线,然后看射线和路径的交点方向,选择一个作为基准方向,如果方向一致则加1,方向不一致则减1。为0时,点不在路径内。

kCAFillRuleEvenOdd:奇偶规则,当这个点作任意方法的射线,射线和路径的交点数量是奇数则认为点在内部。

fillRule

如上图(不知道找什么画图软件好,就用了 Sketch ),如果使用 kCAFillRuleNonZero 规则,则该射线和两条路径相交,并且交点方向都是逆时针,所以点在路径内。
如果使用 kCAFillRuleEvenOdd 规则,则该射线与路径有两个交点,为偶数,所以该点不在范围内。


总结



CAShapeLayer 基本属性不多,主要还是需要通过不断的实践,结合贝塞尔曲线来实现不同的需求。


代码及相关资料



PS



第一次上简书首页,欢迎关注,长期更新 iOS 开发相关文章~~~

推荐阅读更多精彩内容