Calling all experts! I have seen various posts, and to be honest, my need is a little different than the answers available on SO.
I want to create a UI where the user can create various lines (straight, curved, wiggled etc) onto a specific area (lets call this "canvas" for now). There can be multiple instances of each of the lines. The user then has the ability to drag and edit these lines based on their need. So, they can stretch it, change the start point, end point etc, or even drag the entire line to within the bounds of the canvas.
I have managed to draw the line (using drawRect
) and show draggable handles at the ends of each line (see reference image), and the user can drag the end points within the bounds (red rectangle) of the canvas to suit the need.
The problem I am facing is how to tap to activate edit for a particular line. So, by default, the drag handles will not be visible, and the user can tap on the line to activate 'edit' mode lets say, and show the handles (tap again to deselect). So, in the diagram above, I want to be able to detect touches in the yellow rectangle. Keep in mind that the UIView bounds is the entire canvas area, to allow users to drag freely, so detecting touches is clearly difficult since there are transparent areas as well, and there can be multiple instance of each line.
Here's my code so far for the line class (startHandle and endHandle are the handles at each end):
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint startPoint = CGPointMake(self.startHandle.frame.origin.x + self.startHandle.frame.size.width/2, self.startHandle.frame.origin.y + self.startHandle.frame.size.height/2);
CGPoint endPoint = CGPointMake(self.endHandle.frame.origin.x + self.endHandle.frame.size.width/2, self.endHandle.frame.origin.y + self.endHandle.frame.size.height/2);
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
if (CGRectContainsPoint(CGRectMake(startPoint.x, startPoint.y, endPoint.x - startPoint.x , endPoint.y - startPoint.y), touchLocation))
{
//this is the green rectangle! I want the yellow one :)
NSLog(@"TOUCHED IN HIT AREA");
}
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, self.bounds);
CGPoint startPoint = CGPointMake(self.startHandle.frame.origin.x + self.startHandle.frame.size.width/2, self.startHandle.frame.origin.y + self.startHandle.frame.size.height/2);
CGPoint endPoint = CGPointMake(self.endHandle.frame.origin.x + self.endHandle.frame.size.width/2, self.endHandle.frame.origin.y + self.endHandle.frame.size.height/2);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextSetLineWidth(context, 2.0f);
CGContextMoveToPoint(context, startPoint.x, startPoint.y ); //start at this point
CGContextAddLineToPoint(context, endPoint.x, endPoint.y); //draw to this point
self.arrow.angle = [self pointPairToBearingDegrees:startPoint secondPoint:endPoint];
self.arrow.center = endPoint;
[self.arrow setNeedsDisplay];
// and now draw the Path!
CGContextStrokePath(context);
}
Things I have tried so far:
- Try to detect touches within a rectangle drawn between the start point and the end point, but this does return the rectangle I need, since it's of larger area if the angle of the line is lets say 45 degrees (see green rectangle)
- Tried to draw another thicker line on top in drawRect, but in vain, since I would have to make it transparent, and its the same as any other area of the view. Also tried to detect color, but again this thicker line has to be transparent.
I would really appreciate any help in this direction. Bonus points if you can show me how to do this for a curved line. Thank you so much for reading through.
CGPath
. I need to redraw the line every time the user moves the end point or the start point, and CGPath does not perform really well in this situation, or probably I am not doing it the right way. Thanks a lot again! Cheers. – YarboroughCGPath
andCGPathContainsPoint
would be useful in this situation. From the documentation: "A point is contained in a path if it would be inside the painted region when the path is filled." So basically it returns true for points "surrounded" by the path. If you just have a line segment, even if it's curved, it's probably not surrounding anything. – Illusionism