iPhone Multitouch

When handling touch events, the events you get via the touch events in the UIView class is pretty much the raw events from the hardware, wrapped in Objective C objects. If you’re dragging around one finger, then while keeping that finger down touch with a second, you get a new touchesBegan event. Lift the first finger but keep the second, and you get a touchesEnded event for the first finger, but the move events for the second continue.

I suppose this is what one would expect. But it means that if you drag with two fingers, you probably are going to receive touchesMoved events for each finger separately, rather than receiving a touchesMoved event for both fingers at the same time.

This implies that if you want to track all the fingers moving around at the same time, you need to maintain the state of affairs; that is, you need to keep track of the touch events that haven’t moved as well as the ones that have moved.

Here is some code I wrote which keep the current touch events in a secondary set, so I can see and track all the fingers as they move. This isn’t the best code in the world, but it does prove the concept.

@implementation TestTouch

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
		self.multipleTouchEnabled = YES;
		set = [[NSMutableSet alloc] initWithCapacity:10];
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
	[[UIColor whiteColor] setFill];
	UIRectFill(rect);
	
	[[UIColor blackColor] setFill];
	for (UITouch *t in set) {
		CGRect r;
		CGPoint pt = [t locationInView:self];
		r.origin.x = pt.x - 22;
		r.origin.y = pt.y - 22;
		r.size.width = 44;
		r.size.height = 44;
		UIRectFill(r);
	}
}

- (void)dealloc
{
	[set release];
    [super dealloc];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
	for (UITouch *t in touches) {
		[set addObject:t];
	}
	[self setNeedsDisplay];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
	[set removeAllObjects];
	[self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	for (UITouch *t in touches) {
		[set removeObject:t];
	}
	[self setNeedsDisplay];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
	[self setNeedsDisplay];
}

@end

If you need to capture when all the touches start and when they all end, you can do this by testing if the set (defined as NSMutableSet in the class) is empty.

For whatever reason I want to think that the touches set passed is full of all of the fingers, but no–you only get the finger that changed, not the fingers that stayed still or didn’t change. Thus, you need a set to capture them all.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s