Mask shadow CALayer only outside the rectangle

How would I mask a CALayer with a shadow so that the shadow is just out of the way? I do not want a shadow behind a transparent view.

shadowLayer.shadowOffset = CGSizeMake(x, y); shadowLayer.shadowRadius = radius; shadowLayer.shadowOpacity = opacity; shadowLayer.shadowColor = color.CGColor; shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:view.bounds].CGPath; 

Thanks.

+6
source share
3 answers

I will answer my question. Adding a new shadow layer for view . This should work for any shadowPath , if set correctly.

 float radius = 8; float opacity = 0.5f; float x = 4; float y = 6; UIColor *color = [UIColor blackColor]; // Shadow layer CALayer *shadowLayer = [CALayer layer]; shadowLayer.shadowOffset = CGSizeMake(x, y); shadowLayer.shadowRadius = radius; shadowLayer.shadowOpacity = opacity; shadowLayer.shadowColor = color.CGColor; shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:view.frame].CGPath; // Or any other path // Shadow mask frame CGRect frame = CGRectInset(view.layer.frame, -2*radius, -2*radius); frame = CGRectOffset(frame, x, y); // Translate shadowLayer shadow path to mask layer coordinate system CGAffineTransform trans = CGAffineTransformMakeTranslation(-view.frame.origin.x-x+2*radius, -view.frame.origin.y-y+2*radius); // Mask path CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, nil, (CGRect){.origin={0,0}, .size=frame.size}); CGPathAddPath(path, &trans, shadowLayer.shadowPath); CGPathCloseSubpath(path); // Mask layer CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; maskLayer.frame = frame; maskLayer.fillRule = kCAFillRuleEvenOdd; maskLayer.path = path; shadowLayer.mask = maskLayer; [view.layer.superlayer insertSublayer:shadowLayer below:view.layer]; 
+7
source

Just ahead: you can use CAShapeLayer to set the shadow

 let shapeLayer = CAShapeLayer() shapeLayer.lineWidth = 2 shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.strokeColor = UIColor.purple.cgColor shapeLayer.shadowColor = UIColor.black.cgColor shapeLayer.shadowOffset = CGSize(width: 0, height: 3) shapeLayer.shadowOpacity = 1 view.layer.addSublayer(shapeLayer) 
+1
source

Ssteinberg's answer helped me in iOS 10.2 and Swift 3. I was able to use my answer with UIVisualEffectView to create beautiful blur, but also with shadow. Converted to Swift 3 here:

 let shadowLayer = CALayer() let mutablePath = CGMutablePath() let maskLayer = CAShapeLayer() let xOffset = CGFloat(4) let yOffset = CGFloat(6) let shadowOffset = CGSize(width: xOffset, height: yOffset) let shadowOpacity = Float(0.5) let shadowRadius = CGFloat(8) let shadowPath = UIBezierPath(rect: frame).cgPath let shadowColor = UIColor.black let shadowFrame = frame.insetBy(dx: -2 * shadowRadius, dy: -2 * shadowRadius).offsetBy(dx: xOffset, dy: yOffset) let shadowRect = CGRect(origin: .zero, size: shadowFrame.size) let shadowTransform = CGAffineTransform(translationX: -frame.origin.x - xOffset + 2 * shadowRadius, y: -frame.origin.y - yOffset + 2 * shadowRadius) shadowLayer.shadowOffset = shadowOffset shadowLayer.shadowOpacity = shadowOpacity shadowLayer.shadowRadius = shadowRadius shadowLayer.shadowPath = shadowPath shadowLayer.shadowColor = shadowColor.cgColor mutablePath.addRect(shadowRect) mutablePath.addPath(shadowLayer.shadowPath!, transform: shadowTransform) mutablePath.closeSubpath() maskLayer.frame = shadowFrame maskLayer.fillRule = kCAFillRuleEvenOdd maskLayer.path = mutablePath shadowLayer.mask = maskLayer layer.superlayer?.insertSublayer(shadowLayer, above: layer) 
0
source

All Articles