iOS draw Stroked Arc - ios

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.

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.

Draw on UIView or GLKView?

I need to draw a separator line with some dots on it. I have decided I will do this using the draw method, as opposed to including images of the separator. I will do this for performance and for customisability, as the separator changes sometimes.
Now I have looked into the draw() method on UIView and I have noticed that Apple suggests using GLKView when drawing using OpenGL.
For a simple separator, won't it be too much of a hassle to call OpenGL? Or is the OpenGL overhead negligible? When would I want to use the native UIKit draw() then?
FYI I don't know either method, but want to learn both methods, so don't reply "what you know best". I am simply asking about performance.
OpenGL uses GPU instead of CPU for computation. If you are making something like a gaming app, then you can think of using OpenGL. I believe you want to draw a line in an iOS App. For that you can either use drawRect method in UIView or create a shapeLayer and add it as a sublayer.
The following examples will show you:
CAShapeLayer *simpleLine = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, 80)];
[path addLineToPoint:CGPointMake(300, 80)];
simpleLine.lineWidth = 1.0;
simpleLine.path = path.CGPath;
simpleLine.strokeColor = [[UIColor blackColor] CGColor];
[[self.view layer] addSublayer:simpleLine];
For using drawRect, you are supposed to do this inside a Custom UIView as opposed to the above method.
- (void)drawRect:(CGRect)rect {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, 80)];
[path addLineToPoint:CGPointMake(300, 80)];
path.lineWidth = 1.0;
[[UIColor blueColor] setStroke];
[path stroke];
}
If your separator parameters changes and if you are making an app, it's better to use drawRect method. You can call this method anytime by using [CustomUIView setNeedsDisplay:YES]
Edit
What you're asking for is circle over line. You can do that by drawing UIBezierPath for line first and then add UIBezierPath for circle later.
Normal Line
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
Dotted Line
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
shapeLayer.lineDashPattern = #[#4, #2];
[self.view.layer addSublayer:shapeLayer];

How to create a circular dotted line as a CALayer?

I read this post Draw dotted (not dashed!) line, with IBDesignable in 2017 about drawing a dotted line (rather than a dashed line). However, I am not too familiar with graphics generally and I'm wondering how I can do this with a CALayer (so I don't have to do the whole get current graphics context thing).
I am trying to produce a dotted line that looks like this (the white part, ignore the background):
Here's the code I have working to produce a dotted line:
CAShapeLayer *shapelayer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startPoint];
[path addLineToPoint:endPoint];
[path setLineCapStyle:kCGLineCapRound];
UIColor *fill = [UIColor whiteColor];
shapelayer.strokeStart = 0.0;
shapelayer.strokeColor = fill.CGColor;
shapelayer.lineWidth = 4.0;
shapelayer.lineJoin = kCALineJoinRound;
shapelayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:4],[NSNumber numberWithInt:6 ], nil];
shapelayer.path = path.CGPath;
return shapelayer;
How can I mirror the code in the SO post I referenced but continue using a CALayer?
I tried modifying the code from that post like so:
UIBezierPath * path = [[UIBezierPath alloc] init];
[path moveToPoint:startPoint];
[path addLineToPoint:endPoint];
[path setLineWidth:8.0];
CGFloat dashes[] = { path.lineWidth, path.lineWidth * 2 };
[path setLineDash:dashes count:2 phase:0];
[path setLineCapStyle:kCGLineCapRound];
[path stroke];
CAShapeLayer *returnLayer = [CAShapeLayer layer];
returnLayer.path = path.CGPath;
return returnLayer;
However, this ends up drawing nothing.
I hope this will help you.
CAShapeLayer *circleLayer = [CAShapeLayer layer];
[circleLayer setPath:[[UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 100)] CGPath]];
circleLayer.lineWidth = 2.0;
[circleLayer setStrokeColor:[[UIColor redColor] CGColor]];
[circleLayer setFillColor:[[UIColor clearColor] CGColor]];
circleLayer.lineJoin = kCALineJoinRound;
circleLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:2],[NSNumber numberWithInt:3 ], nil];
// self.bgImage is parentView
[[self.bgImage layer] addSublayer:circleLayer];
self.bgImage.layer.borderWidth = 1.0f;
self.bgImage.layer.borderColor = [[UIColor blueColor]CGColor];
I have attached the output of the image
In my case I had to set the lineCapStyle rather than the lineJoinStyle.

How to draw lines with angle and distance in ios

I am having an app in which I am doing some calculations and based on that I want to draw a traverse like shown below.
Here is an image of the traverse.
I have distance of AB, BC and so on.
Based on this values I need to draw an image shown above.
I know how to draw a line using UIBezierPath and using the below code.
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(100.0, 100.0)];
[path addLineToPoint:CGPointMake(100.0, 100.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
But how to draw this with this calculations. I am confused with it. I just want some guidance on it.
My main aim is to draw image with the design pattern shown below.
EDIT
I have a distance of 50.0 and an angle of 37 for line AB. How to draw a line AB from that?
Please help.
Any help will be appreciated. Thanks.
Example:
- (void)drawTraverseWithFirstPoint:(CGPoint)firstPoint secondPoint:(CGPoint)point thirdPoint:(CGPoint)thirdPoint fourthPoint:(CGPoint)fourthPoint andLastPoint:(CGPointLastPoint) {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:your_start_point];
[path addLineToPoint:firstPoint];
[path addLineToPoint:secondPoint];
[path addLineToPoint:thirdPoint];
[path addLineToPoint:fourthPoint];
[path addLineToPoint:lastPoint];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
}
Just do the calculations first and pass it as paramethers or pass an Array with points however it is easier for you, i hope you will understand my example good day.

Animate a point of a Bezier curve [duplicate]

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."

Resources