Search code examples
iosswiftcalayercashapelayer

CAShapeLayer cutout in UIView


My goal is to create a pretty opaque background with a clear rounded rect inset

    let shape = CGRect(x: 0, y: 0, width: 200, height: 200)

    let maskLayer = CAShapeLayer()
    maskLayer.path = UIBezierPath(roundedRect: shape, cornerRadius: 16).cgPath
    maskLayer.fillColor = UIColor.clear.cgColor
    maskLayer.fillRule = kCAFillRuleEvenOdd

    let background = UIView()
    background.backgroundColor = UIColor.black.withAlphaComponent(0.8)
    view.addSubview(background)
    constrain(background) {
        $0.edges == $0.superview!.edges
    }

    background.layer.addSublayer(maskLayer)
//        background.layer.mask = maskLayer

When I uncomment background.layer.mask = maskLayer, the view is totally clear. When I have it commented out, I see the semi-opaque background color but no mask cutout

Any idea what I'm doing wrong here? Thanks!


Solution

  • Here is a playground that I think implements your intended effect (minus .edges and constrain - that appear to be your own extensions).

    a) used a red background instead of black with alpha (just to make the effect stand out)

    b) set maskLayer.backgroundColor instead of maskLayer.fillColor

    Adding the maskLayer as another layer to uiview is superfluous (as indicated by @Ken) but seems to do no harm.

        import UIKit
        import PlaygroundSupport
    
    
        let bounds = CGRect(x: 0, y: 0, width: 400, height: 200)
    
        let uiview = UIView(frame: bounds)
        uiview.backgroundColor = UIColor.red.withAlphaComponent(0.8)
    
        PlaygroundPage.current.liveView = uiview
    
        let shape = CGRect(x: 100, y: 50, width: 200, height: 100)
    
    
        let maskLayer = CAShapeLayer()
        maskLayer.path = UIBezierPath(roundedRect: shape, cornerRadius: 16).cgPath
        maskLayer.backgroundColor = UIColor.clear.cgColor
        maskLayer.fillRule = kCAFillRuleEvenOdd
        uiview.layer.mask = maskLayer
    

    image of clear inset

    On the other hand, if you intended a picture frame / colored-envelope-with-transparent-window effect like below, then see gist

    image of picture frame