Identifying the Type of Touch Gestures from UIEvent Object

user1799795 picture user1799795 · Feb 6, 2013 · Viewed 7.9k times · Source

Is there a way to gain the type of touch gestures that triggered a UIEvent? So, let's say I intercept a gesture with hitTest:withEvent:. How do I identify what kind of touch (pinch, tap, swipe, etc.) happened that triggered this method?

I can gain the type of remote events from the UIEvent subtype, and even if the device was shaken, but there is no parameter for touch events...

How do you identify those?

Answer

sergio picture sergio · Feb 6, 2013

You have to do touch analysis on your own.

It is not that difficult, but it is not done for you. Here a sample from some code I am actually using. It is not meant as a full-scale solution. It only detects basic tap/swipe/pinch gestures in a very concrete context (that of my app), and uses a rather uncool mechanism to deliver the gestures (notifications). So, it might apply to your case or more likely not, but I hope it gives you an idea of what is required.

NSSet* allTouches = [event allTouches];
UITouch* touch = [allTouches anyObject];
UIView* touchView = [touch view];

        if (touch.phase == UITouchPhaseBegan) {

            _initialView = touchView;
            startTouchPosition1 = [touch locationInView:self];
            startTouchTime = touch.timestamp;

            if ([allTouches count] > 1) {
                startTouchPosition2 = [[[allTouches allObjects] objectAtIndex:1] locationInView:self];
                previousTouchPosition1 = startTouchPosition1;
                previousTouchPosition2 = startTouchPosition2;
            }
        }

        if (touch.phase == UITouchPhaseMoved) {

            if ([allTouches count] > 1) {
                CGPoint currentTouchPosition1 = [[[allTouches allObjects] objectAtIndex:0] locationInView:self];
                CGPoint currentTouchPosition2 = [[[allTouches allObjects] objectAtIndex:1] locationInView:self];

                CGFloat currentFingerDistance = CGPointDist(currentTouchPosition1, currentTouchPosition2);
                CGFloat previousFingerDistance = CGPointDist(previousTouchPosition1, previousTouchPosition2);
                if (fabs(currentFingerDistance - previousFingerDistance) > ZOOM_DRAG_MIN) {
                    NSNumber* movedDistance = [NSNumber numberWithFloat:currentFingerDistance - previousFingerDistance];
                    if (currentFingerDistance > previousFingerDistance) {
//                          NSLog(@"zoom in");
                        [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ZOOM_IN object:movedDistance];
                    } else {
//                          NSLog(@"zoom out");
                        [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ZOOM_OUT object:movedDistance];
                    }
                }
            }
        }

        if (touch.phase == UITouchPhaseEnded) {
            CGPoint currentTouchPosition = [touch locationInView:self];

            // Check if it's a swipe
            if (fabsf(startTouchPosition1.x - currentTouchPosition.x) >= SWIPE_DRAG_HORIZ_MIN &&
                fabsf(startTouchPosition1.x - currentTouchPosition.x) > fabsf(startTouchPosition1.y - currentTouchPosition.y) &&
                touch.timestamp - startTouchTime < 0.7) 
            {
                // It appears to be a swipe.
                if (startTouchPosition1.x < currentTouchPosition.x) {
                        NSLog(@"swipe right");
                    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SWIPE_RIGHT object:self];
                } else {
                        NSLog(@"swipe left");
                    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SWIPE_LEFT object:self];
                }
            } else {
                //-- else, check if it's a single touch
                if (touch.tapCount == 1) {
                    NSDictionary* uInfo = [NSDictionary dictionaryWithObject:touch forKey:@"touch"];
                    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_TAP object:self userInfo:uInfo];                        
                }/* else if (touch.tapCount > 1) {
                    handle multi-touch
                }
                */
            }

            startTouchPosition1 = CGPointMake(-1, -1);
            _initialView = nil;
        }

        if (touch.phase == UITouchPhaseCancelled) {
            _initialView = nil;
//          NSLog(@"TOUCH CANCEL");
        }