How to draw shadow around the masked UIView? - ios

I want to make a UIView which will have shape like in Figure 1. and also should have shadow around the shape of my view .
I am using below code to draw CAShaperLayer with UIBezierPath
UIBezierPath *bezier = [UIBezierPath bezierPath];
[bezier moveToPoint:CGPointMake(0,7)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width-15, 7)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width-10,0)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width-5, 7)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width, 7)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width, self.menuView.frame.size.height)];
[bezier addLineToPoint:CGPointMake(0, self.menuView.frame.size.height)];
[bezier closePath];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = [bezier CGPath];
self.menuView.layer.mask = maskLayer;
and for adding shadow
self.menuView.layer.shadowColor = [[UIColor colorWithRed:8.0f/255.0f green:37.0f/255.0f blue:82.0f/225.0f alpha:1] CGColor];
self.menuView.layer.shadowOffset = CGSizeZero;
self.menuView.layer.shadowOpacity = 0.3f;
self.menuView.layer.shadowRadius = 5.0f;
self.menuView.layer.masksToBounds=NO;
My Problem :
After masking CAShaperLayer on menuView ,the shadow has disappeared . Figure 2
Instead of Masking View , i also tried to add Sublayer on it
[self.menuView.layer addSublayer:maskLayer]
but this will hide my all SubViews of MenuView Figure 3
(I have changed the CASahperLayer Color to Black just to show )
🔹 My Question is :
What is the best way to get the perfect shape with shadow as shown in Figure 1 ???.
(Thanks in advance)

extension UIView{
func viewShadowBorder() {
self.layer.shadowColor = UIColor.gray.cgColor
self.layer.shadowOpacity = 1
self.layer.shadowOffset = CGSize.zero
self.layer.shadowRadius = 2
self.layer.cornerRadius = 2
}
}

Related

CAShapeLayer draws a circle in center as a sideeffect of line cap set to kCALineJoinRound

I'm drawing a segment of a pie chart with the following code:
CAShapeLayer *segment = [CAShapeLayer layer];
UIBezierPath *segmentPath = [UIBezierPath bezierPath];
[segmentPath addArcWithCenter:segmentCenter radius:segmentRadius startAngle:angle1 endAngle:angle2 clockwise:YES];
segment.path = [segmentPath CGPath];
[segment setLineCap:kCALineJoinRound]; // this is the line which causes this
segment.lineWidth = 8;
segment.fillColor = [[UIColor clearColor] CGColor];
segment.strokeColor = [[UIColor orangeColor] CGColor];
[self.layer addSublayer:segment];
and as a sideffect of setting kCALineJoinRound I get also a little circle inside. I need to get rid of it, can you help me?
Solved, the problem was due to the CAShapeLayer being added twice in layoutSubviews which caused this strange effect.

Implement drawing gradient arc with CAShapeLayer

Referring to the accepted answer found here I'm trying to implement this and running into an issue with the path of the CAShapeLayerThe code I have is as follows:
-(void)drawGradientArc{
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
CAShapeLayer *circleLayer = [CAShapeLayer new];
circleLayer.lineWidth = 25;
circleLayer.fillColor = [UIColor clearColor].CGColor;
circleLayer.strokeColor = [UIColor redColor].CGColor;
CGFloat radius = 150;
[bezierPath addArcWithCenter:self.view.center radius:radius startAngle:0 endAngle:M_PI clockwise:YES];
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0,0);
gradientLayer.endPoint = CGPointMake(1,0);
NSMutableArray *colors = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
[colors addObject:(id)[[UIColor colorWithHue:(0.1 * i) saturation:1 brightness:.8 alpha:1] CGColor]];
}
gradientLayer.colors = colors;
[gradientLayer setMask:circleLayer];
circleLayer.path = bezierPath.CGPath;
[self.view.layer addSublayer:circleLayer];
}
This will draw the half circle arc correctly but the path for the gradients is not being set correctly and I was unable to piece together how exactly to configure the code to get this to work using a gradient. There is a CGPathCreateCopyByStrokingPath that I think I may also need to call to set the path properly for the gradient but was not quite sure how. Any help on how to structure the code to get this working would be appreciated. I've also included an image of the gradient that I'm trying to reproduce. a CAShapeLayer and CAGradientLayerapproach would be ideal.
Problem 1: Your layers have no frames. Add this:
gradientLayer.frame = self.view.layer.bounds;
circleLayer.frame = gradientLayer.bounds;
Problem 2: You are adding the wrong layer to your view's layer. Where you have:
[self.view.layer addSublayer:circleLayer];
say this instead:
[self.view.layer addSublayer:gradientLayer];
Result:

iOS UIButton with custom shapes

How to create 2 buttons in iOS with custom shapes. I need to draw two buttons like Diagonal of a rectangle. Left side is one button and right side is another button. I've tried using Bezier paths, But how to make them adaptive for all devices ?
Here is my code that I've tried for one button
UIBezierPath* bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 138, 118)];
[UIColor.blackColor setStroke];
bezierPath.lineWidth = 20;
[bezierPath stroke];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.frame = self.Btn.bounds;
shapeLayer.path = bezierPath.CGPath;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.strokeColor = [UIColor blackColor].CGColor;
shapeLayer.lineWidth = 120;
self.Btn.layer.mask = shapeLayer;
cant u just do one button,
subclass it and hittest the CGPoint to determine which shape you should set highlighted/selected/etc

Cutting a layer out of a layer

So I'm trying to cut a circle out of an existing layer; and here's my code:
CGRect bounds = _containerLayer.bounds;
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.fillColor = [UIColor blackColor].CGColor;
CGFloat smallCircleRadius = (frame.size.width - barWidth)/2;
CGRect smallCircleRect = CGRectMake(CGRectGetMidX(bounds) - smallCircleRadius, CGRectGetMidY(bounds) - smallCircleRadius, 2 * smallCircleRadius, 2 * smallCircleRadius);
UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:smallCircleRect];
[circlePath appendPath:[UIBezierPath bezierPathWithRect:bounds]];
maskLayer.path = circlePath.CGPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
_containerLayer.mask = maskLayer;
This code does work, as I now see a black rectangle with a hollow circle in the middle. But the problem is that when I tried to set maskLayer.fillColor = [UIColor clearColor].CGColor;, The whole thing including _containerLayer just disappears - I want to make the fillColor transparent so I can see what's originally in the _containerLayer (which wasn't cut out). What should I do to achieve this? Thanks!

Drawing dashed line in CAShapeLayer

I'm drawing a UIBezierPath into a CAShapeLayer, because I want to use strokeStart and strokeEnd to control which sections of the path are drawn. Everything works fine except lineDashPattern is being ignored. What am I doing wrong?
I have tried using setLineDash on the UIBezierPath itself. It works if I stroke the path directly into the context (using [path stroke]), but doesn't help if I assign the CGPath to the shapeLayer, which is what I need.
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
UIGraphicsPushContext(context);
CAShapeLayer *shapeLayer = (CAShapeLayer *)layer;
UIBezierPath *path = [MyMapPath pathForMap:nil];
shapeLayer.path = path.CGPath;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 6.0f;
shapeLayer.lineDashPattern = #[#2,#2];
shapeLayer.strokeStart = 0.0f;
shapeLayer.strokeEnd = 0.7f;
UIGraphicsPopContext();
}

Resources