Search code examples
ioscore-animation

Is there a way to prevent CALayer shadows from overlapping adjacent layers?


I have a collection of CALayers. Each layer is a sublayer of the same parent CALayer, and each has a shadow applied to it. The layers are positioned dynamically, and there are many of them, so I can't predict how they'll be arranged ahead of time.

If the layers are adjacent to each other (close enough that they are almost touching) the shadow of one of the CALayers is rendered on top of the other CALayer. That's probably the desired effect in most cases, but I want my layers to exist in the same z-plane. (An example of this is the way CSS3 shadows are applied to block elements in web design.)

Is this possible? How can I achieve this?

(I had this idea: Adding a 'shadow' sublayer to each CALayer with my own shadow image, and setting the z-position to a lower value. But doesn't the layer-tree make this impossible? Z-positions in one layer's coordinate system are independent from z-positions in another layer's coordinate system, right?)


Solution

  • If all of the shadowed layers have the same shadow settings, put them into a container layer and set the shadow on the container layer. Example:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        CALayer *containerLayer = [CALayer layer];
        containerLayer.frame = self.view.bounds;
        containerLayer.shadowRadius = 10;
        containerLayer.shadowOpacity = 1;
        [self.view.layer addSublayer:containerLayer];
    
        CAShapeLayer *layer1 = [CAShapeLayer layer];
        layer1.bounds = CGRectMake(0, 0, 200, 200);
        layer1.position = CGPointMake(130, 130);
        layer1.path = [UIBezierPath bezierPathWithOvalInRect:layer1.bounds].CGPath;
        layer1.fillColor = [UIColor redColor].CGColor;
        [containerLayer addSublayer:layer1];
    
        CAShapeLayer *layer2 = [CAShapeLayer layer];
        layer2.bounds = CGRectMake(0, 0, 200, 200);
        layer2.position = CGPointMake(170, 200);
        layer2.path = [UIBezierPath bezierPathWithOvalInRect:layer2.bounds].CGPath;
        layer2.fillColor = [UIColor blueColor].CGColor;
        [containerLayer addSublayer:layer2];
    }
    

    Output:

    overlapping circles with unified shadow