Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a shadow to CAShapeLayer, so that the inside remains transparent

I want to add a glow effect to a path, like the blue glow around (OS X) interface elements when they have focus.

I used a CAShapeLayer with a (rectangular) path:

self.borderLayer = [CAShapeLayer layer];
CGPathRef path = CGPathCreateWithRect(self.bounds, NULL);
[self.borderLayer setPath:path];
CGPathRelease(path);

In the end this gives me a transparent UIView with a border around it. (In my concrete case it's a dashed line with an additional animation, but that doesn't matter for this particular question)

I played around with the shadow properties of CALayer, but they will always fill the whole layer.

self.borderLayer.shadowPath = self.borderLayer.path;
self.borderLayer.shouldRasterize = YES;

What I want is that only the UIViews surrounding line drops a shadow, so that the inside of the UIView remains transparent.

like image 322
Patrick Avatar asked May 08 '13 15:05

Patrick


2 Answers

I was having similar problems seeing the shadow inside where I wanted it instead of a glow. I solved it by using two CALayers. One, in the code, '_bg' for the background ( in my case black with opacity of 0.55) and a white border. The other layer, in the code '_shadow', has a clear background and adds the glow effect. _bg is a subview of the _shadow layer. Here's the relevant code:

_bg = [CALayer layer];
_shadow = [CALayer layer];

[self.layer insertSublayer:_shadow atIndex:0];
[_shadow addSublayer:_bg];

_bg.frame = self.bounds;
_bg.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:.55].CGColor;
_bg.cornerRadius=20.0;
_bg.borderColor=[UIColor whiteColor].CGColor;
_bg.borderWidth=2.0;

_shadow.frame=self.bounds;
_shadow.masksToBounds=NO;
_shadow.backgroundColor = [UIColor clearColor].CGColor;
_shadow.cornerRadius=3.0;
_shadow.shadowRadius=3.0;
_shadow.shadowColor=[UIColor whiteColor].CGColor;
_shadow.shadowOpacity=0.6;
_shadow.shadowOffset=CGSizeMake(0.0, 0.0);
like image 200
ModernCarpentry Avatar answered Oct 22 '22 00:10

ModernCarpentry


You can try something like this:

    //background layer of the shadow layer
    contentViewBackgroundLayer = [CALayer layer];
    contentViewBackgroundLayer.frame = contentView.bounds;
    contentViewBackgroundLayer.backgroundColor = someColor.CGColor;
    //shadow layer
    contentViewShadowLayer = [CALayer layer];
    [contentViewShadowLayer addSublayer:contentViewBackgroundLayer];
    contentViewShadowLayer.backgroundColor = [UIColor clearColor].CGColor;
    //shadowRadius
    contentViewShadowLayer.shadowRadius = 10.0;
    contentViewShadowLayer.shadowColor = [UIColor blackColor].CGColor;
    contentViewShadowLayer.shadowOpacity = 0.5;
    contentViewShadowLayer.shadowOffset = CGSizeMake(0.0, 0.0);
    //Important!!!!  add mask to shadowLayer
    contentViewBackgroundLayer.frame = contentView.bounds;
    contentViewShadowLayer.frame = contentView.bounds;
    CGRect rect = CGRectMake(contentViewShadowLayer.bounds.origin.x - 20, contentViewShadowLayer.bounds.origin.y - 20, contentViewShadowLayer.bounds.size.width + 40, contentViewShadowLayer.bounds.size.height + 40);
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect];
    [path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, contentView.bounds.size.width, contentView.bounds.size.height)]];
    //a rectangle which is transparent surrounded by a bigger rectangle
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.fillRule = kCAFillRuleEvenOdd;
    shapeLayer.path = [path CGPath];
    contentViewShadowLayer.mask = shapeLayer;
    [contentView.layer insertSublayer:contentViewShadowLayer atIndex:0];
like image 34
lihk11 Avatar answered Oct 21 '22 23:10

lihk11