I am working on a drawing project, I want to support multitouch, I have gone through documentation online, which suggest to track the touch points, I did it , But I am not getting the desired behaviour. I am not getting straight lines.
Below is my code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
red = 0.0/255.0;
green = 0.0/255.0;
blue = 0.0/255.0;
brush = 10.0;
opacity = 1.0;
self.view.multipleTouchEnabled = YES;
touchPaths = [NSMutableDictionary dictionary];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches)
{
NSString *key = [NSString stringWithFormat:@"%d", (int) touch];
lastPoint = [touch locationInView:self.view];
[touchPaths setObject:[NSValue valueWithCGPoint:lastPoint] forKey:key];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
NSString *key = [NSString stringWithFormat:@"%d", (int) touch];
lastPoint = [[touchPaths objectForKey:key] CGPointValue];
CGPoint currentPoint1 = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint1.x, currentPoint1.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self.tempDrawImage setAlpha:opacity];
UIGraphicsEndImageContext();
lastPoint = currentPoint1;
}
}
But when I draw using this code, I get this.
So friends, please help me out, what I am doing wrong.
Regards
Ranjit
You are not populating the touchPaths
properly. Try setting it after each drawing instead, something like this:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
NSString *key = [NSString stringWithFormat:@"%d", (int) touch];
CGPoint lastPoint = [[touchPaths objectForKey:key] CGPointValue];
CGPoint currentPoint1 = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint1.x, currentPoint1.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self.tempDrawImage setAlpha:opacity];
UIGraphicsEndImageContext();
// I changed your code here
[touchPaths setObject:[NSValue valueWithCGPoint:currentPoint1] forKey:key];
}
}
You are currently setting lastPoint
here but you do not seem to use it (and it would only work with one touch). There is no need to have lastPoint
as a field either.
I always try to use gesture-recognizers when possible. Here I use the UIPanGestureRecognizer
:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didPan:)]];
}
- (void)didPan:(UIPanGestureRecognizer*)panGesture {
for (NSUInteger touchIndex = 0; touchIndex < panGesture.numberOfTouches; touchIndex++) {
// touchIndex is basically the "source" (the finger) from which the point comes from
CGPoint p = [panGesture locationOfTouch:touchIndex inView:self.view];
[self drawAtPoint:p withIndex:touchIndex];
}
}
- (void)drawAtPoint:(CGPoint)point withIndex:(NSUInteger)index{
UIView *smallPoint = [[UIView alloc] initWithFrame:CGRectMake(point.x, point.y, 3, 3)];
[smallPoint setBackgroundColor:[self colorForIndex:index]];
[self.view addSubview:smallPoint];
}
- (UIColor*)colorForIndex:(NSUInteger)index {
switch (index) {
case 0: return [UIColor redColor];
case 1: return [UIColor orangeColor];
case 2: return [UIColor yellowColor];
case 3: return [UIColor blueColor];
case 4: return [UIColor greenColor];
}
return [UIColor clearColor];
}
I don't draw a bezier path, but if you drop it in an empty ViewController and run it, you will see that when multi-touching the screen, each finger draws a different colour.
So if you take into consideration the touchIndex, basically you can keep track of different paths for different fingers.
Let's say you use two fingers to draw: you will have panGesture.numberOfTouches == 2
, and touchIndex 0
will represent the first finger, and touchIndex 1
will represent the second finger. You can accumulate the points in different arrays and add the points to their corresponding path.