Search code examples
iosswiftcocoa-touchuiviewuibezierpath

Shadow on UIView layer


I've make a path in order to mask my view:

let path = // create magic path (uiview bounds + 2 arcs)
let mask = CAShapeLayer()
mask.path = path.cgPath
view.layer.masksToBounds = false
view.layer.mask = mask

Up to here all ok.

Now I would like to add a shadow that follows path, is it possibile?

I try in several way, the last one is:

mask.shadowPath = path.cgPath
mask.shadowColor = UIColor.red.cgColor
mask.shadowOffset = CGSize(width: 10, height: 2.0)       
mask.shadowOpacity = 0.5

But this produce a partial shadow and with color of the original view..

enter image description here

With debug view hierarchy:

enter image description here

Any advice?

Final result should be similar to this, but with shadow that "follows" arcs on path.

enter image description here


Solution

  • When you add a mask to a layer, it clips anything outside that mask - including the shadow. To achieve this you'll need to add a "shadow" view below your masked view, that has the same path as the mask.

    Or add a shadow layer to the masked view's superview.

    let view = UIView(frame: CGRect(x: 50, y: 70, width: 100, height: 60))
    view.backgroundColor = .cyan
    
    let mask = CAShapeLayer()
    mask.path = UIBezierPath(roundedRect: view.bounds, cornerRadius: 10).cgPath
    view.layer.mask = mask
    
    let shadowLayer = CAShapeLayer()
    shadowLayer.frame = view.frame
    shadowLayer.path = UIBezierPath(roundedRect: view.bounds, cornerRadius: 10).cgPath
    shadowLayer.shadowOpacity = 0.5
    shadowLayer.shadowRadius = 5
    shadowLayer.masksToBounds = false
    shadowLayer.shadowOffset = .zero    
    
    let container = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
    container.backgroundColor = .white
    container.layer.addSublayer(shadowLayer)
    container.addSubview(view)
    

    enter image description here

    If you're going to be using this elsewhere, you could create a ShadowMaskedView that contains the shadow layer, and the masked view - maybe with a path property.