14
- (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--;
    }
}

When I pan gesture move to left ,then move to right. it will use right . I want to How to know pan gesture change direction?

Jiang Yufeng
  • 189
  • 1
  • 1
  • 8
  • try this [http://stackoverflow.com/a/5187591/5575752](http://stackoverflow.com/a/5187591/5575752) – Ronak Chaniyara Jan 28 '16 at 08:12
  • Possible duplicate of [Detecting the direction of PAN gesture in iOS](https://stackoverflow.com/questions/11777281/detecting-the-direction-of-pan-gesture-in-ios) – Ivan Smetanin Jul 11 '19 at 06:42

5 Answers5

34

Try this,

- (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer
{
    CGPoint velocity = [gestureRecognizer velocityInView:yourView];

    if(velocity.x > 0)
    {
        NSLog(@"gesture moving right");
    }
    else
    {
        NSLog(@"gesture moving left");
    }

     if(velocity.y > 0)
    {
        NSLog(@"gesture moving Up");
    }
    else
    {
        NSLog(@"gesture moving Bottom");
    }

}
Manikandan D
  • 1,422
  • 1
  • 13
  • 25
11

This bit of code extends Luca Davanzo's answer with an OptionSet to get correct results when you want to handle moving in multiple directions.

Swift 3.1

extension UIPanGestureRecognizer {

    public struct PanGestureDirection: OptionSet {
        public let rawValue: UInt8

        public init(rawValue: UInt8) {
            self.rawValue = rawValue
        }

        static let Up = PanGestureDirection(rawValue: 1 << 0)
        static let Down = PanGestureDirection(rawValue: 1 << 1)
        static let Left = PanGestureDirection(rawValue: 1 << 2)
        static let Right = PanGestureDirection(rawValue: 1 << 3)
    }

    private func getDirectionBy(velocity: CGFloat, greater: PanGestureDirection, lower: PanGestureDirection) -> PanGestureDirection {
        if velocity == 0 {
            return []
        }
        return velocity > 0 ? greater : lower
    }

    public func direction(in view: UIView) -> PanGestureDirection {
        let velocity = self.velocity(in: view)
        let yDirection = getDirectionBy(velocity: velocity.y, greater: PanGestureDirection.Down, lower: PanGestureDirection.Up)
        let xDirection = getDirectionBy(velocity: velocity.x, greater: PanGestureDirection.Right, lower: PanGestureDirection.Left)
        return xDirection.union(yDirection)
    }
}

Use it like this:

let direction = panGestureRecognizer.direction(in: superview)
if direction.contains(.Left) && direction.contains(.Down) {
    // do stuff
} else if direction.contains(.Up) {
    // ...
}
David
  • 2,109
  • 1
  • 22
  • 27
  • This works great, thanks. Though users of this should note that even if drag left to right, if there is an smidge of a south direction, it will trigger .Down. – micnguyen Jul 09 '18 at 04:58
  • Is there a way to reduce the sensitivty so that it won't trigger the other directions? I tried playing with the velocity values but it didn't help. – kobowo Mar 06 '19 at 02:35
7

In Swift I create my own extension easy to use everywhere you have a UIPanGestureRecognizer.

extension UIPanGestureRecognizer {

    enum GestureDirection {
        case Up
        case Down
        case Left
        case Right
    }

    /// Get current vertical direction
    ///
    /// - Parameter target: view target
    /// - Returns: current direction
    func verticalDirection(target target: UIView) -> GestureDirection {
        return self.velocityInView(target).y > 0 ? .Down : .Up
    }

    /// Get current horizontal direction
    ///
    /// - Parameter target: view target
    /// - Returns: current direction
    func horizontalDirection(target target: UIView) -> GestureDirection {
        return self.velocityInView(target).x > 0 ? .Right : .Left
    }

    /// Get a tuple for current horizontal/vertical direction
    ///
    /// - Parameter target: view target
    /// - Returns: current direction
    func versus(target target: UIView) -> (horizontal: GestureDirection, vertical: GestureDirection) {
        return (self.horizontalDirection(target: target), self.verticalDirection(target: target))
    }

}

You can use in this way:

override viewDidLoad() {
    super.viewDidLoad()
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(ViewController.didSwipeOnView(_:)))
    self.addGestureRecognizer(panGesture) 
}

func didSwipeOnView(gestureRecognizer: UIPanGestureRecognizer) {
    if case .Down = gestureRecognizer.verticalDirection(target: self) {
       print("Swiping down")
    } else {
       print("Swiping up")
    }
}
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
  • What if the velocity (x/y) equals zero? In your `func versus(target:)` you return a tuple with 2 directions when in fact you can sometimes move in one direction only. – David Mar 07 '17 at 14:18
  • Are you sure that this situation may occur? I'm not sure.. but, in case, I can improve with a new GestureDirection => None – Luca Davanzo Mar 07 '17 at 14:23
2

Swift 3

Create the gesture and attach it to your view:

let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handleGesture))
yourView.addGestureRecognizer(panGesture)

Create a class variable that will hold the value of the latest direction:

var latestDirection: Int = 0

Panning on yourView will trigger the gesture handler where we check if pan direction was changed:

func handleGesture(gesture: UIPanGestureRecognizer) {
  let velocity = gesture.velocity(in: yourView)
  var currentDirection: Int = 0

  if velocity.x > 0 {
    print("panning right")
    currentDirection = 1
  } else {
    print("panning left")
    currentDirection = 2
  }

  // check if direction was changed
  if currentDirection != latestDirection {
    print("direction was changed")
  }

  latestDirection = currentDirection
}

This only handles direction change between left and right pan, but if someone wants to detect pan up/down, add this code to handleGesture function:

if velocity.y > 0 {
  print("panning down")
} else {
  print("panning up")
}
budiDino
  • 13,044
  • 8
  • 95
  • 91
1

Swift 5.x

extension UIPanGestureRecognizer {

    public struct PanGestureDirection: OptionSet {
        public let rawValue: UInt8

        public init(rawValue: UInt8) {
            self.rawValue = rawValue
        }

        static let Up = PanGestureDirection(rawValue: 1 << 0)
        static let Down = PanGestureDirection(rawValue: 1 << 1)
        static let Left = PanGestureDirection(rawValue: 1 << 2)
        static let Right = PanGestureDirection(rawValue: 1 << 3)
    }

    public func direction(in view: UIView) -> PanGestureDirection {
        let velocity = self.velocity(in: view)
        let isVerticalGesture = abs(velocity.y) > abs(velocity.x)
        if isVerticalGesture {
            return velocity.y > 0 ? .Down : .Up
        } else {
            return velocity.x > 0 ? .Right : .Left
        }
    }
}
Giang
  • 2,384
  • 2
  • 25
  • 26