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
Related
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
}
}
I am currently using CAShapeLayer for one of my requirement. I was successful in implementing the fillcolor, strokecolor, etc... but I wanted to change the color of outer part of that CAShapeLayer. I tried doing it with backgroundcolor, & followed many answers from SO, but was unable to do it. Could anyone guide me with the solution. Screenshot attached
Edit 1: Code for creating the layer
// create layer mask for map
CAShapeLayer *maskLayer = [CAShapeLayer layer];
mapView.layer.mask = maskLayer;
// maskLayer.backgroundColor = [[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.7] CGColor];
self.maskLayer = maskLayer;
// create shape layer for circle we'll draw on top of map (the boundary of the circle)
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.lineWidth = 3.0;
circleLayer.fillColor = [[UIColor clearColor] CGColor];
circleLayer.strokeColor = [[UIColor blackColor] CGColor];
// circleLayer.borderColor = [[UIColor blackColor] CGColor];
// circleLayer.backgroundColor = [[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.7] CGColor];
[mapView.layer addSublayer:circleLayer];
self.circleLayer = circleLayer;
Edit 2: Xcode's Viewer's Debugger
In the above image I can see that I have set the background color to self.view. But I want it to be over my map view & the the color should be semi transparent so that map data outside circle should also be visible.
Have you tried using XCode views's debugger to know where this white background belongs in your view hierarchy ?
You're using your view's maskLayer as a circle. So my guess is that this white background must be OUTSIDE your view - everything out your mask gets clipped - so you should probably try to change your viewController's view backgroundColor (or any other view that is just above your custom rounded view)
[self.view.layer setBackgroundColor:[UIColor grayColor].CGColor];
UIBezierPath *circle = [UIBezierPath bezierPathWithArcCenter:self.view.center
radius:45.0
startAngle:0
endAngle:2.0*M_PI
clockwise:YES];
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.bounds = CGRectMake(0, 0, 2.0*(45.0), 2.0*(45.0));
circleLayer.path = circle.CGPath;
circleLayer.strokeColor = [UIColor orangeColor].CGColor;
circleLayer.fillColor = [UIColor whiteColor].CGColor;
circleLayer.lineWidth = 3.0; // your line width
[self.view.layer addSublayer:circleLayer];
See if it helps you.
I'm trying to draw filled and stroked arc. Please see this image(Left: what i have. Right: what i need]):
I don't know how to set arcs join behaviour. Here is the code(arrowLayer is a CAShapeLayer):
UIBezierPath *arcPath = [UIBezierPath bezierPath];
[arcPath addArcWithCenter:CGPointMake(frame.size.width/2, frame.size.height/2)
radius:65
startAngle:DEGREES_TO_RADIANS(-10)
endAngle:DEGREES_TO_RADIANS(320)
clockwise:YES];
[arcPath addArcWithCenter:CGPointMake(frame.size.width/2, frame.size.height/2)
radius:55
startAngle:DEGREES_TO_RADIANS(-10)
endAngle:DEGREES_TO_RADIANS(320)
clockwise:YES];
arrowLayer.path = [arcPath CGPath];
arrowLayer.fillColor = [UIColor clearColor].CGColor;
arrowLayer.strokeColor = [[UIColor redColor] CGColor];
arrowLayer.lineWidth = 1.0;
Additional Question:
How to get start and end points coords of arc, is it possible? It needs to complete the second part of my task.
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();
}
This question already has an answer here:
How to Animate a UIBezierPath
(1 answer)
Closed 9 years ago.
Is is possible to animate a point of a bezier curve? I am trying make a smooth transition from a line to an arrow.
Here's what the line looks like in code
//// Color Declarations
UIColor* white = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0.374];
//// Group
{
//// Bezier Drawing
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint: CGPointMake(30.5, 43.5)];
[bezierPath addLineToPoint: CGPointMake(30.5, 29.59)];
[bezierPath addLineToPoint: CGPointMake(30.5, 15.5)];
bezierPath.lineCapStyle = kCGLineCapRound;
bezierPath.lineJoinStyle = kCGLineJoinBevel;
[white setStroke];
bezierPath.lineWidth = 5.5;
[bezierPath stroke];
}
... however I do not know how to pick a point and animate just that. Is this even possible?
Explicit CGPath animation using a CAShapeLayer:
// Create the starting path. Your curved line.
UIBezierPath * startPath;
// Create the end path. Your straight line.
UIBezierPath * endPath;
// Create the shape layer to display and animate the line.
CAShapeLayer * myLineShapeLayer = [[CAShapeLayer alloc] init];
CABasicAnimation * pathAnimation = [CABasicAnimation animationWithKeyPath:#"path"];
pathAnimation.fromValue = (__bridge id)[startPath CGPath];
pathAnimation.toValue = (__bridge id)[endPath CGPath];
pathAnimation.duration = 5.0f;
[myLineShapeLayer addAnimation:pathAnimation forKey:#"animationKey"];
It isn't clear what you are asking. Are you trying to animate changing the shape of your line by moving one of the control points?
The way to animate changes to paths is to create a CAShapeLayer and install it as a sublayer of your view's layer. Then if you change the path associated with the shape layer the system will use implicit animation to make the change.
Note that the path in the shape layer needs to have the same number/type of control points or the results of the animation are "undefined."