Search code examples
iphoneiosuigesturerecognizerswipeosx-chameleon

How to implement swipe with UIGestureRecognizer subclass


How do you implement a swipe with an UIGestureRecognizer subclass?

(in case you're wondering why I'd like to do this instead of using UISwipeGestureRecognizer, it's because I want to add swipe recognition to Chameleon's UIKit port)


Solution

  • My first go at it (also on Github):

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        UITouch *touch = [touches anyObject];
        _beganLocation = [touch locationInView:self.view];
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
        UITouch *touch = [touches anyObject];
        CGPoint movedLocation = [touch locationInView:self.view];
        CGFloat distance = _distance(_beganLocation, movedLocation);
    
        if (distance < SWIPE_MIN_DISTANCE) return;
    
        CGFloat angle = _angle(_beganLocation, movedLocation);
        int direction = -1;
        if (angle > 270 - SWIPE_MAX_ANGLE && angle < 270 + SWIPE_MAX_ANGLE) {
            direction = UISwipeGestureRecognizerDirectionUp;
        }
        if (angle > 180 - SWIPE_MAX_ANGLE && angle < 180 + SWIPE_MAX_ANGLE) {
            direction = UISwipeGestureRecognizerDirectionLeft;
        }
        if (angle > 90 - SWIPE_MAX_ANGLE && angle < 90 + SWIPE_MAX_ANGLE) {
            direction = UISwipeGestureRecognizerDirectionDown;
        }
        if ((angle > 360 - SWIPE_MAX_ANGLE && angle <= 360) || (angle >= 0 && angle <= SWIPE_MAX_ANGLE)) {
            direction = UISwipeGestureRecognizerDirectionRight;
        }
    
        if (direction == -1) {
          self.state = UIGestureRecognizerStateFailed;
        } else {
          self.state = self.direction == direction ? UIGestureRecognizerStateRecognized : UIGestureRecognizerStateFailed;
        }
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
        self.state = UIGestureRecognizerStateFailed;
    }
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
        self.state = UIGestureRecognizerStateFailed;
    }
    

    Auxiliary functions:

    static CGFloat _distance(CGPoint point1,CGPoint point2)
    {
        CGFloat dx = point2.x - point1.x;
        CGFloat dy = point2.y - point1.y;
        return sqrt(dx*dx + dy*dy);
    };
    
    static CGFloat _angle(CGPoint start, CGPoint end)
    {
        CGPoint origin = CGPointMake(end.x - start.x, end.y - start.y); // get origin point to origin by subtracting end from start
        CGFloat radians = atan2f(origin.y, origin.x); // get bearing in radians
        CGFloat degrees = radians * (180.0 / M_PI); // convert to degrees
        degrees = (degrees > 0.0 ? degrees : (360.0 + degrees)); // correct discontinuity
        return degrees;
    }
    

    It should be noted that Chameleon's implementation of gesture recognizers is incomplete and contains logic most likely specific to Twitterrific. Our fork contains further modifications.