Archive for 23rd July 2009

Simple swipe detection in the iPhone SDK

A quick round of hallway usability testing of my iPhone app revealed that apparently, iPhone and iPod Touch users like to swipe and don’t have any idea that the UIPageControl (the bar with the little white dots that show which page of information you are on) can be tapped on to move the page number. Instead, my admittedly small sample size of 2 (thanks John and Ben) were trying to swipe all over the view to move it from one page to another. As a result, I set out to try and find information about detecting the swipe motion in the iPhone SDK.

Quick searches of the internet and documentation did not reveal any immediate solutions, so I set about on the task of trying to figure out how to do it on my own. The first thing I noticed is that you can hook into the touchesBegan event for the view, so I created this code:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	CGPoint pt;
	NSSet *allTouches = [event allTouches];
	if ([allTouches count] == 1)
	{
		UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
		if ([touch tapCount] == 1)
		{
			pt = [touch locationInView:self.view];
			touchBeganX = pt.x;
			touchBeganY = pt.y;
		}
	}
}

(After adding the following variable definitions at the top of my view controller implementation file, of course.)

int touchBeganX, touchBeganY;

So now I have the position where a single touch began. The next thing I thought I would do would be to subclass the touchesEnded event, but for some reason, the tapCount of the touch that I read in touchesEnded would be zero, and that seemed a little confusing to me as to why that would be. I then turned to the touchesMoved event:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	CGPoint pt;
	NSSet *allTouches = [event allTouches];
	if ([allTouches count] == 1)
	{
		UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
		if ([touch tapCount] == 1)
		{
			pt = [touch locationInView:self.view];
			touchMovedX = pt.x;
			touchMovedY = pt.y;
		}
	}
}

Yes, this looks shockingly similar to the code for touchesBegan. By the way, don’t forget more variable definitions:

int touchMovedX, touchMovedY;

I can now track where the touch began and the last place it moved to. I then swing back around to the touchesEnded event to do the actual swipe detection, as even though the tapCount is zero, I think I can safely determine that a single touch and drag event occurred and then test it to see if it is a swipe.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	NSSet *allTouches = [event allTouches];
	if ([allTouches count] == 1)
	{
		int diffX = touchMovedX - touchBeganX;
		int diffY = touchMovedY - touchBeganY;
		if (diffY >= -20 && diffY <= 20) 		
		{
 			if (diffX > 20)
			{
				NSLog(@"swipe right");
				// do something here
			}
			else if (diffX < -20)
			{
				NSLog(@"swipe left");
				// do something else here
			}
		}
	}
}

Perhaps reading swipes is so simple to do in the iPhone SDK that I missed it in the docs or online. If anyone has any better ways to do this, or a web site or blog post that explains it better, please let me know.


Somewhat related, somewhat unrelated tangent alert:

My father used to have this bag that said “I Like Swipe”, I think he said that he used to sell the product when he was a boy back in the 1940s, it was some kind of cleaning chemical. I wish he still had that bag, it was pretty retro looking and a picture of it would have fit in perfectly with this posting. I guess I will just have to settle with this:
&quot;I Like Swipe&quot;