UIGestureRecognizer Tutorial in iOS 5: Pinches, Pans, and More!
Update 7/17/14: We now have a new version of this tutorial fully updated to Swift – check it out! If you need to detect gestures in your app, such as taps, pinches, pans, or rotations, it’s extremely easy with the built-in UIGestureRecognizer classes. In this tutorial, we’ll show you how you can easily add gesture […] By Ray Wenderlich.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
UIGestureRecognizer Tutorial in iOS 5: Pinches, Pans, and More!
25 mins
Update 7/17/14: We now have a new version of this tutorial fully updated to Swift – check it out!
If you need to detect gestures in your app, such as taps, pinches, pans, or rotations, it’s extremely easy with the built-in UIGestureRecognizer classes.
In this tutorial, we’ll show you how you can easily add gesture recognizers into your app, both within the Storyboard editor in iOS 5, and programatically.
We’ll create a simple app where you can move a monkey and a banana around by dragging, pinching, and rotating with the help of gesture recognizers.
We’ll also demonstrate some cool extras like:
- Adding deceleration for movement
- Setting gesture recognizers dependency
- Creating a custom UIGestureRecognizer so you can tickle the monkey! :]
This tutorial assumes you are familiar with the basic concepts of ARC and Storyboards in iOS 5. If you are new to these concepts, you may wish to check out our ARC and Storyboard tutorials first.
I think the monkey just gave us the thumbs up gesture, so let’s get started! :]
Getting Started
Open up Xcode and create a new project with the iOS\Application\Single View Application template. For the Product Name enter MonkeyPinch, for the Device Family choose iPhone, and select the Use Storyboard and Use Automatic Reference Counting checkboxes, as shown below.
First, download the resources for this project and add the four files inside into your project. In case you’re wondering, the images for this tutorial came from my lovely wife’s free game art pack, and we made the sound effects ourselves with a mike :P
Next, open up MainStoryboard.storyboard, and drag an Image View into the View Controller. Set the image to monkey_1.png, and resize the Image View to match the size of the image itself by selecting Editor\Size to Fit Content. Then drag a second image view in, set it to object_bananabunch.png, and also resize it. Arrange the image views however you like in the view controller. At this point you should have something like this:
That’s it for the UI for this app – now let’s add a gesture recognizer so we can drag those image views around!
UIGestureRecognizer Overview
Before we get started, let me give you a brief overview of how you use UIGestureRecognizers and why they’re so handy.
In the old days before UIGestureRecognizers, if you wanted to detect a gesture such as a swipe, you’d have to register for notifications on every touch within a UIView – such as touchesBegan, touchesMoves, and touchesEnded. Each programmer wrote slightly different code to detect touches, resulting in subtle bugs and inconsistencies across apps.
In iOS 3.0, Apple came to the rescue with the new UIGestureRecognizer classes! These provide a default implementation of detecting common gestures such as taps, pinches, rotations, swipes, pans, and long presses. By using them, not only does it save you a ton of code, but it makes your apps work properly too!
Using UIGestureRecognizers is extremely simple. You just perform the following steps:
- Create a gesture recognizer. When you create a gesture recognizer, you specify a callback method so the gesture recognizer can send you updates when the gesture starts, changes, or ends.
- Add the gesture recognizer to a view. Each gesture recognizer is associated with one (and only one) view. When a touch occurs within the bounds of that view, the gesture recognizer will look to see if it matches the type of touch it’s looking for, and if a match is found it will notify the callback method.
You can perform these two steps programatically (which we’ll do later on in this tutorial), but it’s even easier adding a gesture recognizer visually with the Storyboard editor. So let’s see how it works and add our first gesture recognizer into this project!
UIPanGestureRecognizer
Still with MainStoryboard.storyboard open, look inside the Object Library for the Pan Gesture Recognizer, and drag it on top of the monkey Image View. This both creates the pan gesture recognizer, and it with the monkey Image View. You can verify you got it connected OK by clicking on the monkey Image View, looking at the Connections Inspector, and making sure the Pan Gesture Recognizer is in the gestureRecognizers collection:
You may wonder why we associated it to the image view instead of the view itself. Either approach would be OK, it’s just what makes most sense for your project. Since we tied it to the monkey, we know that any touches are within the bounds of the monkey so we’re good to go. The drawback of this method is sometimes you might want touches to be able to extend beyond the bounds. In that case, you could add the gesture recognizer to the view itself, but you’d have to write code to check if the user is touching within the bounds of the monkey or the banana and react accordingly.
Now that we’ve created the pan gesture recognizer and associated it to the image view, we just have to write our callback method so we can actually do something when the pan occurs.
Open up ViewController.h and add the following declaration:
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer;
Then implement it in ViewController.m as follows:
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
The UIPanGestureRecognizer will call this method when a pan gesture is first detected, and then continuously as the user continues to pan, and one last time when the pan is complete (usually the user lifting their finger).
The UIPanGestureRecognizer passes itself as an argument to this method. You can retrieve the amount the user has moved their finger by calling the translationInView method. Here we use that amount to move the center of the monkey the same amount the finger has been dragged.
Note it’s extremely important to set the translation back to zero once you are done. Otherwise, the translation will keep compounding each time, and you’ll see your monkey rapidly move off the screen!
Note that instead of hard-coding the monkey image view into this method, we get a reference to the monkey image view by calling recognizer.view. This makes our code more generic, so that we can re-use this same routine for the banana image view later on.
OK, now that this method is complete let’s hook it up to the UIPanGestureRecognizer. Select the UIPanGestureRecongizer in Interface Builder, bring up the Connections inspector, and drag a line from the selector to the View Controller. A popup will appear – select handlePan. At this point your Connections Inspector for the Pan Gesture Recognizer should look like this:
Compile and run, and try to drag the monkey and… wait, it doesn’t work!
The reason this doesn’t work is that touches are disabled by default on views that normally don’t accept touches, like Image Views. So select both image views, open up the Attributes Inspector, and check the User Interaction Enabled checkbox.
Compile and run again, and this time you should be able to drag the monkey around the screen!
Note that you can’t drag the banana. This is because gesture recognizers should be tied to one (and only one) view. So go ahead and add another gesture recognizer for the banana, by performing the following steps:
- Drag a Pan Gesture Recognizer on top of the banana Image View.
- Select the new Pan Gesture Recognizer, select the Connections Inspector, and drag a line from the selector to the View Controller and connect it to the handlePan method.
Give it a try and you should now be able to drag both image views across the screen. Pretty easy to implement such a cool and fun effect, eh?