Warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'quick_page_post_reds::ppr_filter_page_links ' was given in /home/mindtr74/public_html/wp-includes/plugin.php on line 199
Gesture Recognizer Tips and Tricks [iOS] | Mind Treat Studios
Warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'quick_page_post_reds::ppr_filter_page_links ' was given in /home/mindtr74/public_html/wp-includes/plugin.php on line 199

Warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'quick_page_post_reds::ppr_filter_page_links ' was given in /home/mindtr74/public_html/wp-includes/plugin.php on line 199

Warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'quick_page_post_reds::ppr_filter_page_links ' was given in /home/mindtr74/public_html/wp-includes/plugin.php on line 199

Warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'quick_page_post_reds::ppr_filter_page_links ' was given in /home/mindtr74/public_html/wp-includes/plugin.php on line 199

Gesture Recognizer Tips and Tricks [iOS]

Starting with iOS 3.2 Apple introduced a new easier way for developers to detect and use standard gestures in their applications.

They created UIGestureRecognizer and its sub-classes for dealing with this. You can now safely and easily detect the following:

I will not describe each gesture individually since there are some very good tutorials out there. I will just share some neat methods of combining these to detect more complex gestures.

Simultaneous Pan and Pinch Gesture Recognition
Image your user trying to view a picture in your awesome app. We want him to be able to zoom (pinch gesture) or drag around the picture (pan gesture) without lifting the fingers from the surface.

Here is some example code on how to setup your recognizers to achieve this behavior:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void)setupRecognizers
{
    UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognized:)];
    panRecognizer.minimumNumberOfTouches = 1;
    panRecognizer.delegate = self; // Very important
    [someView addGestureRecognizer:panRecognizer];
 
    UIPinchGestureRecognizer* pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self     action:@selector(pinchGestureRecognized:)];
    pinchRecognizer.delegate = self; // Very important
    [someView addGestureRecognizer:pinchRecognizer];
}
 
#pragma mark - UIGestureRecognizerDelegate
 
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer <strong>shouldRecognizeSimultaneouslyWithGestureRecognizer</strong>:(UIGestureRecognizer *)otherGestureRecognizer
{
    // If you have multiple gesture recognizers in this delegate, you can filter them by comparing the gestureRecognizer parameter to your saved objects
    return YES; // Also, very important.
}

As you can see, the trick is to add a delegate to both recognizers, and the return TRUE in the implemented delegate method. You can share the delegate object with other recognizers without any problems.

 Improved Pan and Swipe Gesture Recognition

The standard UISwipeGestureRecognizer is good, but not great. For example, it has no way of controlling the minimum acceleration you must have when performing the gesture.

To go around this problem I used a pan gesture recognizer to detect the swipes. The good news is that you can even use the same recognizer to perform panning and swiping detection. Here is some example code on how to use it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
- (void)setupRecognizer
{
    UIPanGestureRecognizer* panSwipeRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanSwipe:)];
    // Here you can customize for example the minimum and maximum number of fingers required
    panSwipeRecognizer.minimumNumberOfTouches = 2;
    [targetView addGestureRecognizer:panSwipeRecognizer];
}
 
#define SWIPE_UP_THRESHOLD -1000.0f
#define SWIPE_DOWN_THRESHOLD 1000.0f
#define SWIPE_LEFT_THRESHOLD -1000.0f
#define SWIPE_RIGHT_THRESHOLD 1000.0f
 
- (void)handlePanSwipe:(UIPanGestureRecognizer*)recognizer
{
    // Get the translation in the view
    CGPoint t = [recognizer translationInView:recognizer.view];
    [recognizer setTranslation:CGPointZero inView:recognizer.view];
 
    // TODO: Here, you should translate your target view using this translation
    someView.center = CGPointMake(someView.center.x + t.x, someView.center.y + t.y);
 
    // But also, detect the swipe gesture
    if (recognizer.state == UIGestureRecognizerStateEnded)
    {
        CGPoint vel = [recognizer velocityInView:recognizer.view];
 
        if (vel.x < SWIPE_LEFT_THRESHOLD)
        {
            // TODO: Detected a swipe to the left
        }
        else if (vel.x > SWIPE_RIGHT_THRESHOLD)
        {
            // TODO: Detected a swipe to the right
        }
        else if (vel.y < SWIPE_UP_THRESHOLD)
        {
            // TODO: Detected a swipe up
        }
        else if (vel.y > SWIPE_DOWN_THRESHOLD)
        {
            // TODO: Detected a swipe down
        }
        else
        {
            // TODO:
            // Here, the user lifted the finger/fingers but didn't swipe.
            // If you need you can implement a snapping behaviour, where based on the location of your         targetView,
            // you focus back on the targetView or on some next view.
            // It's your call
        }
    }
}

Finally, you can even combine the 2 methods above to achieve an even more complete recognition solution.