Luca Davanzo
Luca Davanzo

Reputation: 21520

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

Upvotes: 7

Views: 3142

Answers (2)

vatanak
vatanak

Reputation: 1

You can try this extension:

extension UIView {

    func dropShadow() {

        self.layer.masksToBounds = false
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowOpacity = 0.5
        self.layer.shadowOffset = CGSize(width: -1, height: 1)
        self.layer.shadowRadius = 1

        self.layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
        self.layer.shouldRasterize = true
    }
}

Upvotes: -1

Ashley Mills
Ashley Mills

Reputation: 53111

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.

Upvotes: 9

Related Questions