LinusG.
LinusG.

Reputation: 28952

Draw drop shadow only on one view below

I have a UIView with a drop shadow. I want the shadow to be drawn only on a single view below. The problem is, that the view below's bounds are smaller.

Current result:

current result

Desired result:

desired result

Note:

The user dynamically updates the screen by dragging the blue view in or out. Hence, the solution can't be static.

Is there any way to achieve this?

Upvotes: 0

Views: 254

Answers (2)

Johnny Rockex
Johnny Rockex

Reputation: 4196

  1. Create a holder view.
  2. Create two shapes: the blue box and the grey box.
  3. Combine the paths you used for the two boxes to create a third shape for masking the holder view.

enter image description here

UIView * background = [UIView new];
background.frame = self.view.bounds;
background.backgroundColor = [self colourForHex:@"#F5F5F5" andAlpha:1.0f];
[self.view addSubview:background];

UIView * holder = [UIView new];
holder.frame = CGRectMake((w-300)/2, (h-300)/2, 300, 300);
[background addSubview:holder];

UIBezierPath * boxPath = [UIBezierPath bezierPath];
[boxPath moveToPoint:CGPointMake(0, 0)];
[boxPath addLineToPoint:CGPointMake(0, 100)];
[boxPath addLineToPoint:CGPointMake(200, 100)];
[boxPath addLineToPoint:CGPointMake(200, 0)];
[boxPath closePath];

UIBezierPath * castPath = [UIBezierPath bezierPath];
[castPath moveToPoint:CGPointMake(10, 100)];
[castPath addLineToPoint:CGPointMake(0, 200)];
[castPath addLineToPoint:CGPointMake(200, 200)];
[castPath addLineToPoint:CGPointMake(190, 100)];
[castPath closePath];

CAShapeLayer * boxShape = [CAShapeLayer layer];
boxShape.path = boxPath.CGPath;
boxShape.fillColor = [self colourForHex:@"#1A0F53" andAlpha:1.0f].CGColor;
boxShape.shadowColor = [UIColor blackColor].CGColor;
boxShape.shadowOffset = CGSizeMake(5, 5);
boxShape.shadowRadius = 2.0f;
boxShape.shadowOpacity = 0.5f;
[holder.layer addSublayer:boxShape];

CAShapeLayer * castShape = [CAShapeLayer layer];
castShape.path = castPath.CGPath;
castShape.fillColor = [self colourForHex:@"#D8D8D8" andAlpha:1.0f].CGColor;
[holder.layer insertSublayer:castShape below:boxShape];

UIBezierPath * maskPath = [UIBezierPath bezierPath];
[maskPath appendPath:boxPath];
[maskPath appendPath:castPath];

CAShapeLayer * maskShape = [CAShapeLayer layer];
maskShape.path = maskPath.CGPath;
[holder.layer setMask:maskShape];

EDIT per comment: to add the animation shown in the gif, you can add a UIPanGestureRecogniser to the view and offset as the user slides (original requirement) or, in the above, I added some code like this:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

[UIView animateWithDuration:0.5f
                      delay:0.0f
                    options:UIViewAnimationOptionCurveEaseInOut
                 animations:^{
                     boxShape.transform = CATransform3DMakeTranslation(100, 0, 0);
                 }
                 completion:^(BOOL finished){
                 }];
            });

Upvotes: 1

Luan Lai
Luan Lai

Reputation: 483

Try this:

  1. Gray view: set cliptobounds = true
  2. blue view should NOT be a child of gray view, and doesn't have shadow.
  3. create a subview in gray view, which looks exactly like the blue view, set shadow for this subview.

Upvotes: 2

Related Questions