如何在CAShapeLayer上仅填充形状的一部分

巴纳哥达

我正在使用UIBezierPath创建以下形状,然后使用CAShapeLayer如下绘制它。

在此处输入图片说明

然后,我可以将CAShapeLayer fillColor属性从更改shapeLayer.fillColor = UIColor.clear.cgColorshapeLayer.fillColor = UIColor.blue.cgColor并获得以下形状。

在此处输入图片说明

这是代码:

import UIKit

class ViewController: UIViewController {

    var line = [CGPoint]()
    let bezierPath: UIBezierPath = UIBezierPath()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        let point1 = CGPoint(x: 100, y: 100)
        let point2 = CGPoint(x: 400, y: 100)

        line.append(point1)
        line.append(point2)

        addCircle(toRight: false)
        addLine()
        addCircle(toRight: true)

        let shapeLayer = CAShapeLayer()
        shapeLayer.path = bezierPath.cgPath
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.fillColor = UIColor.clear.cgColor

         self.view.layer.addSublayer(shapeLayer)
    }

    func addLine() -> Void {
        bezierPath.move(to: line.first!)
        bezierPath.addLine(to: line.last!)
    }

    func addCircle(toRight: Bool) -> Void {
        let angle = CGFloat( Double.pi / 180 )
        let r = CGFloat(20.0)
        let x0 = toRight ? line.first!.x : line.last!.x
        let y0 = toRight ? line.first!.y : line.last!.y
        let x1 =  toRight ? line.last!.x : line.first!.x
        let y1 = toRight ? line.last!.y : line.first!.y
        let x = x1 - x0
        let y = y1 - y0
        let h = (x*x + y*y).squareRoot()
        let x2 = x0 + (x * (h + r) / h)
        let y2 = y0 + (y * (h + r) / h)

        // Add the arc, starting at that same point
        let point2 = CGPoint(x: x2, y: y2)
        let pointZeroDeg = CGPoint(x: x2 + r, y: y2)
        self.bezierPath.move(to: pointZeroDeg)
        self.bezierPath.addArc(withCenter: point2, radius: r,
                          startAngle: 0*angle, endAngle: 360*angle,
                          clockwise: true)
        self.bezierPath.close()
    }
}

但是我真正想要的是跟随形状(填充左侧圆,不填充右侧圆)。

在此处输入图片说明

所以我的问题是,如何仅填充CAShapeLayer上的一部分形状?可能吗?有什么技巧可以实现这一目标吗?

PS:我可以通过创建3个不同的UIBezierPaths(分别用于leftCircle,line和rightCircle)并使用以下3个不同的CAShapeLayers进行绘制来实现此目的。

// left Circle
shapeLayer1.path = bezierPath1.cgPath
shapeLayer1.fillColor = UIColor.blue.cgColor

// line
shapeLayer2.path = bezierPath2.cgPath

// right Circle
shapeLayer3.path = bezierPath3.cgPath
shapeLayer3.fillColor = UIColor.clear.cgColor

self.view.layer.addSublayer(shapeLayer1)
self.view.layer.addSublayer(shapeLayer2)
self.view.layer.addSublayer(shapeLayer3)

But I prefer to achieve this with a single CAShapeLayer.

Denis Kreshikhin

I think better approach is using of multiple shapes.

However you can make one-shape implementation by using evenOdd rule of shape filling.

Just add an extra circle to the right circle in method addCircle:

if toRight {
    self.bezierPath.addArc(withCenter: point2, radius: r,
                      startAngle: 0*angle, endAngle: 2*360*angle,
                      clockwise: true)
} else {
    self.bezierPath.addArc(withCenter: point2, radius: r,
                      startAngle: 0*angle, endAngle: 360*angle,
                      clockwise: true)
}

And set fillRule to evenOdd:

shapeLayer.fillColor = UIColor.blue.cgColor        
shapeLayer.fillRule = .evenOdd

So you'll get that the left circle will have one circle of drawing and will be filled by evenOdd rule. But right circle will have two circles of drawing and will be unfilled.

The evenOdd rule (https://developer.apple.com/documentation/quartzcore/cashapelayerfillrule/1521843-evenodd):

指定奇偶缠绕规则。计算过路通道的总数。如果交叉点数为偶数,则该点位于路径之外。如果交叉点的数量为奇数,则该点在路径内,并且应填充包含该点的区域。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章