Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting the direction of PAN gesture in iOS

People also ask

What is Pan gesture in iOS?

A pan gesture occurs any time the user moves one or more fingers around the screen. A screen-edge pan gesture is a specialized pan gesture that originates from the edge of the screen. Use the UIPanGestureRecognizer class for pan gestures and the UIScreenEdgePanGestureRecognizer class for screen-edge pan gestures.

How do you use pan gestures?

The user must press one or more fingers on a view while panning on the screen. A panning gesture is on continuous action when the user moves one or more fingers allowed (minimumNumberOfTouches) to enough distance for recognition as a pan.

How do I add swipe gestures in iOS?

Add four swipe gesture recognizers to your view. Set each one with the target direction from the attribute inspector. You can select right, left, up or down. One by one, select the swipe gesture recognizer, control + drag to your view controller.

How do I use UITapGestureRecognizer?

The iOS UITapGestureRecognizer class has a built-in way to detect a double tap on any view. All you need to do is create the recognizer, set its numberOfTapsRequired property to 2, then add it to the view you want to monitor.


In the target selector of your gesture recognizer, use - (CGPoint)velocityInView:(UIView *)view;:

- (void)panRecognized:(UIPanGestureRecognizer *)rec
{
    CGPoint vel = [rec velocityInView:self.view];
    if (vel.x > 0)
    {
        // user dragged towards the right
        counter++;
    }
    else
    {
        // user dragged towards the left
        counter--;
    }
}

P.s.: I didn't know about this method until approx. 3 minutes before. One of Google's first hits was the official Apple documentation.


Something like this:

- (void)pan:(UIPanGestureRecognizer *)sender
{

    typedef NS_ENUM(NSUInteger, UIPanGestureRecognizerDirection) {
        UIPanGestureRecognizerDirectionUndefined,
        UIPanGestureRecognizerDirectionUp,
        UIPanGestureRecognizerDirectionDown,
        UIPanGestureRecognizerDirectionLeft,
        UIPanGestureRecognizerDirectionRight
    };

    static UIPanGestureRecognizerDirection direction = UIPanGestureRecognizerDirectionUndefined;

    switch (sender.state) {

        case UIGestureRecognizerStateBegan: {

            if (direction == UIPanGestureRecognizerDirectionUndefined) {

                CGPoint velocity = [sender velocityInView:recognizer.view];

                BOOL isVerticalGesture = fabs(velocity.y) > fabs(velocity.x);

                if (isVerticalGesture) {
                    if (velocity.y > 0) {
                        direction = UIPanGestureRecognizerDirectionDown;
                    } else {
                        direction = UIPanGestureRecognizerDirectionUp;
                    }
                }

                else {
                    if (velocity.x > 0) {
                        direction = UIPanGestureRecognizerDirectionRight;
                    } else {
                        direction = UIPanGestureRecognizerDirectionLeft;
                    }
                }
            }

            break;
        }

        case UIGestureRecognizerStateChanged: {
            switch (direction) {
                case UIPanGestureRecognizerDirectionUp: {
                    [self handleUpwardsGesture:sender];
                    break;
                }
                case UIPanGestureRecognizerDirectionDown: {
                    [self handleDownwardsGesture:sender];
                    break;
                }
                case UIPanGestureRecognizerDirectionLeft: {
                    [self handleLeftGesture:sender];
                    break;
                }
                case UIPanGestureRecognizerDirectionRight: {
                    [self handleRightGesture:sender];
                    break;
                }
                default: {
                    break;
                }
            }
        }

        case UIGestureRecognizerStateEnded: {
            direction = UIPanGestureRecognizerDirectionUndefined;   
            break;
        }

        default:
            break;
    }

}

- (void)handleUpwardsGesture:(UIPanGestureRecognizer *)sender
{
    NSLog(@"Up");
}

- (void)handleDownwardsGesture:(UIPanGestureRecognizer *)sender
{
    NSLog(@"Down");
}

- (void)handleLeftGesture:(UIPanGestureRecognizer *)sender
{
    NSLog(@"Left");
}

- (void)handleRightGesture:(UIPanGestureRecognizer *)sender
{
    NSLog(@"Right");
}

My previous answer in Swift

public enum Direction: Int {
    case Up
    case Down
    case Left
    case Right

    public var isX: Bool { return self == .Left || self == .Right }
    public var isY: Bool { return !isX }
}

public extension UIPanGestureRecognizer {

    public var direction: Direction? {
        let velocity = velocityInView(view)
        let vertical = fabs(velocity.y) > fabs(velocity.x)
        switch (vertical, velocity.x, velocity.y) {
        case (true, _, let y) where y < 0: return .Up
        case (true, _, let y) where y > 0: return .Down
        case (false, let x, _) where x > 0: return .Right
        case (false, let x, _) where x < 0: return .Left
        default: return nil
        }
    }
}

Here is a cleaned up Swift 5 version, with example of usage:

public enum PanDirection: Int {
    case up, down, left, right
    public var isVertical: Bool { return [.up, .down].contains(self) }
    public var isHorizontal: Bool { return !isVertical }
}

public extension UIPanGestureRecognizer {

   var direction: PanDirection? {
        let velocity = self.velocity(in: view)
        let isVertical = abs(velocity.y) > abs(velocity.x)
        switch (isVertical, velocity.x, velocity.y) {
        case (true, _, let y) where y < 0: return .up
        case (true, _, let y) where y > 0: return .down
        case (false, let x, _) where x > 0: return .right
        case (false, let x, _) where x < 0: return .left
        default: return nil
        }
    }

}

@IBAction func pan(_ recognizer: UIPanGestureRecognizer) {        
    if let direction = recognizer.direction {
        if direction.isVertical {
            //do what you want when pan is vertical
        } else if direction == .left {
            //do what you want when pan is left
        }
    }
}

Rewrite Adam Waite version on Swift 3

public enum PanDirection: Int {
    case up,
    down,
    left,
    right

    public var isX: Bool {
        return self == .left || self == .right
    }

    public var isY: Bool {
        return !isX
    }
}

extension UIPanGestureRecognizer {
    var direction: PanDirection? {
        let velocity = self.velocity(in: view)
        let vertical = fabs(velocity.y) > fabs(velocity.x)
        switch (vertical, velocity.x, velocity.y) {
        case (true, _, let y):
            return y < 0 ? .up : .down

        case (false, let x, _):
            return x > 0 ? .right : .left
        }
    }
}