Pregunta sobre calayer, uikit, objective-c, core-graphics – Recortar un CAShapeLayer recuperando la ruta externa

7

Estoy tratando de recortar una capa con otra, pero, en lugar de crear una máscara (B) y recortar la capa (A) obteniendo una capa recortada A con la forma de B, quiero obtener una capa con la forma A y una ' agujero 'creado por el recorte con la capa B.

*************               ***Layer A***
*  Layer A  *               *************
*   *****   *               ****    *****
*   * B *   *      ->       ****    ***** Layer A without shape B
*   *****   *               ****    *****
*           *               *************
*************               *************

¿Cómo puedo obtener la capa recortada A?

Tu respuesta

2   la respuesta
20

Tienes que crear una máscara que cubra el área que deseasmantener. Esto se puede hacer usando una regla de relleno impar y crear una ruta para una capa de forma con ambos rectángulos. Puede crear la forma de esta manera (donde los dos rectángulos serían sus dos cuadros). Luego configura esto como la máscara para obtener el resultado que está buscando.

CAShapeLayer *maskWithHole = [CAShapeLayer layer];

// Both frames are defined in the same coordinate system
CGRect biggerRect = CGRectMake(30, 50, 120, 200);
CGRect smallerRect = CGRectMake(80, 100, 50, 80);

UIBezierPath *maskPath = [UIBezierPath bezierPath];
[maskPath moveToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMaxY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMaxY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(biggerRect), CGRectGetMinY(biggerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(biggerRect), CGRectGetMinY(biggerRect))];

[maskPath moveToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMaxY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMaxY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMaxX(smallerRect), CGRectGetMinY(smallerRect))];
[maskPath addLineToPoint:CGPointMake(CGRectGetMinX(smallerRect), CGRectGetMinY(smallerRect))];

[maskWithHole setPath:[maskPath CGPath]];
[maskWithHole setFillRule:kCAFillRuleEvenOdd];
[maskWithHole setFillColor:[[UIColor orangeColor] CGColor]];
0

Solución Swift 3.0:

class MakeTransparentHoleOnOverlayView: UIView {

    @IBOutlet weak var transparentHoleView: UIView!

    // MARK: - Drawing

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        if self.transparentHoleView != nil {
            // Ensures to use the current background color to set the filling color
            self.backgroundColor?.setFill()
            UIRectFill(rect)

            let layer = CAShapeLayer()
            let path = CGMutablePath()

            // Make hole in view's overlay
            // NOTE: Here, instead of using the transparentHoleView UIView we could use a specific CFRect location instead...
            path.addRect(transparentHoleView.frame)
            path.addRect(bounds)

            layer.path = path
            layer.fillRule = kCAFillRuleEvenOdd
            self.layer.mask = layer
        }
    }

    override func layoutSubviews () {
        super.layoutSubviews()
    }

    // MARK: - Initialization

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }
}

Preguntas relacionadas