Use Your Loaf

[[brain engage] write]

iPad Gestures

Apple has added the ability to detect a number of common gestures such as tapping, swiping, pinching and rotating directly into iPhone OS 3.2.

Gesture Recognizers

Prior to the iPad and iPhone OS 3.2 if you wanted to detect a user touching the interface you needed to interact directly with touch events using methods such as touchesBegan and touchesEnd. Since these are touch based devices it always seemed strange to me that the SDK did not provide convenience methods to detect the most common gestures such as a swipe or double-click.

Finally with the introduction of OS 3.2 on the iPad Apple has introduced gesture recognizers which make the whole thing super easy. To detect a particular gesture you create and configure a gesture recognizer which is then added to the view that a user is touching. The following gesture recognizer classes are defined:

UITapGestureRecognizer - single or multiple taps. Configure the number of taps and number of touches required (e.g. double tap with three fingers)

UIPinchGestureRecognizer - zoom in or out using a two finger pinch

UIPanGestureRecognizer - dragging a view with one or more fingers. Configure the minimum and maximum number of fingers required. By default one or more fingers can be used but you could for example require that at least two fingers are used.

UISwipeGestureRecogniser - swiping in any direction. Configure the number of fingers required and the permitted directions of the swipe. So you could recognise a two finger swipe up or down but ignore left to right swipes.

UIRotationGestureRecognizer - two fingers rotating. The resulting gesture includes the rotation and velocity of the movement.

UILongPressGestureRecognizer - one or more fingers touching a view for a minimum period of time. Configure the minimum duration, number of taps, number of fingers and the maximum amount in pixels the fingers are allowed to move. The default duration is 0.4 seconds.

Add gestures to a view

The process of adding a gesture to a view is very simple. The required gesture recognizer is allocated and initialised with a target object and the selector for a method to handle the gesture. The following example sets up recognizers for single-finger and two-finger double taps. The target object is the view controller (self) and we specify two action methods, handleDoubleTap and handleTwoFingerDoubleTap which will be called when the user performs the gesture:

- (void)viewDidLoad { 
  [super viewDidLoad];

  // Single finger, double tap
  UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]
        initWithTarget:self action:@selector(handleDoubleTap)];
  doubleTap.numberOfTapsRequired = 2;
  [self.view addGestureRecognizer:doubleTap];
  [doubleTap release];

  // Two finger, double tap
  UITapGestureRecognizer *twoFingerDoubleTap = [[UITapGestureRecognizer alloc]
        initWithTarget:self action:@selector(handleTwoFingerDoubleTap)];
  twoFingerDoubleTap.numberOfTapsRequired = 2;
  twoFingerDoubleTap.numberOfTouchesRequired = 2;
  [self.view addGestureRecognizer:twoFingerDoubleTap];
  [twoFingerDoubleTap release];
}

The two action methods are as follows (obviously they would normally do something more useful):

- (void)handleDoubleTap {
    NSLog(@"Single finger, double tap");
}

- (void)handleTwoFingerDoubleTap {
    NSLog(@"Two finger, double tap");
}

As with most action methods there are several possible selectors. In the above example we have the simplest case with an action method without parameters. For situations where we want to look at the recognizer in the action method you define a method which takes a gesture recognizer as its parameter as in the following example for detecting swipes:

- (void)viewDidLoad {
  [super viewDidLoad];

  // Swipe Left
  UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] 
        initWithTarget:self action:@selector(handleSwipeLeft:)];
  swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
  [self.view addGestureRecognizer:swipeLeft];
  [swipeLeft release];

  // Swipe Right
  UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] 
        initWithTarget:self action:@selector(handleSwipeRight:)];
  swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
  [self.view addGestureRecognizer:swipeRight];
  [swipeRight release];
}

Note that in this case the selector includes a “:” indicating the presence of a parameter. The action methods for this example would be as follows:

- (void)handleSwipeLeft:(UISwipeGestureRecognizer *)recognizer {
  CGPoint location = [recognizer locationInView:self.view];
  NSLog(@"Swipe left started at (%f,%f)",location.x,location.y);
}

- (void)handleSwipeRight:(UISwipeGestureRecognizer *)recognizer {
  CGPoint location = [recognizer locationInView:self.view];
  NSLog(@"Swipe right started at (%f,%f)",location.x,location.y);
}

Gestures in Universal Apps

Using the new gesture recognizers saves a lot of code. It may also have the added benefit of ensuring Apps implement the more complex gestures in a consistent way. The only thing you have to remember is that the gesture recognizers are iPhone OS 3.2 only. So if you developing universal apps that need to also run on iPhone OS 3.1.x or earlier you will still need to manually code the gestures for those platforms.

Comments