ddolce
ddolce

Reputation: 815

UISwipeGestureRecognizer only one direction working

So Im making a page with pageControl (it's a page with multiple views with dots indicating which page you're in), my code looks like the following in viewDidLoad:

UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];
UIView *temp = [[UIView alloc]initWithFrame:self.view.frame];
temp.backgroundColor = [UIColor clearColor];
[temp addGestureRecognizer:swipe];
[self.view addSubview:temp];

And in the swipeAction selector I have:

- (void)swipeAction: (UISwipeGestureRecognizer *)sender{
    NSLog(@"Swipe action called");
    if (sender.direction == UISwipeGestureRecognizerDirectionLeft) {
        //Do Something
    }
    else if (sender.direction == UISwipeGestureRecognizerDirectionRight){
        //Do Something Else
    }
}

To my surprise, this method only works when you swipe to the right (i.e. the else if block gets called). When you swipe left, the swipeAction doesn't even get called! This is strange, why does this happen and how should I change my code? Any reply is appreciated. Thanks a lot!

Upvotes: 6

Views: 6955

Answers (4)

Xtian D.
Xtian D.

Reputation: 483

I was facing the same issue and found a way by extending the UIPanGestureRecognizer in order to implement a UIDirectionalSwipeGestureRecognizer as follows. The direction of the swipe is available as a public property of the recognizer's instance:

import UIKit

public final class UIDirectionalSwipeGestureRecognizer: UIPanGestureRecognizer {
    
    public private(set) var direction: UISwipeGestureRecognizer.Direction?
    
    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        
        direction = nil
        
        if let touch = touches.first {
            startTimestamp = touch.timestamp
            startLocation = touch.location(in: nil)
        }
    }
    
    public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        
        if
            let currentTimestamp = touches.first?.timestamp,
            let startTimestamp = startTimestamp,
            currentTimestamp - startTimestamp > 0.3
        {
            touchesCancelled(touches, with: event)
        }
    }
    
    public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesEnded(touches, with: event)
        
        if
            let endLocation = touches.first?.location(in: nil),
            let startLocation = startLocation,
            startLocation.distance(to: endLocation) > 20
        {
            direction = UISwipeGestureRecognizer.Direction.fromPoint(startLocation, to: endLocation)
        }
    }
    
    // MARK: - Private
    
    private var startTimestamp: TimeInterval?
    private var startLocation: CGPoint?
}

// MARK: - Extensions

public extension CGPoint {
    
    func distanceSquared(to: CGPoint) -> CGFloat {
        (to.x - x) * (to.x - x) + (to.y - y) * (to.y - y)
    }
    
    func distance(to: CGPoint) -> CGFloat {
        sqrt(distanceSquared(to: to))
    }
}

extension UISwipeGestureRecognizer.Direction {
    
    public static func fromPoint(_ startPoint: CGPoint, to endPoint: CGPoint) -> Self {
        let offset = CGSize(width: endPoint.x - startPoint.x, height: endPoint.y - startPoint.y)
        
        if abs(offset.width) > abs(offset.height) {
            return offset.width > 0 ? .right : .left
        } else {
            return offset.height > 0 ? .up : .down
        }
    }
}


Upvotes: 0

Andrew Hodel
Andrew Hodel

Reputation: 35

Swift 4

let swiper = UISwipeGestureRecognizer(target: self, action: #selector(self.swipeFunction(sender:)))
swiper.direction = UISwipeGestureRecognizer.Direction.right
let swipel = UISwipeGestureRecognizer(target: self, action: #selector(self.swipeFunction(sender:)))
swipel.direction = UISwipeGestureRecognizer.Direction.left
UIView().addGestureRecognizer(swiper)
UIView().addGestureRecognizer(swipel)

@objc func swipeFunction(sender: UISwipeGestureRecognizer) {
    print(sender)
}

you should be able to figure it out from there, you add a UISwipeGestureRecognizer for each direction to the UIView

Upvotes: 2

Mick MacCallum
Mick MacCallum

Reputation: 130193

There's a couple things you should be aware of here. First, you have to create a gesture for each direction that you want to observe. This isn't a big deal though because you can simple give them the same selector, and it will be just like one gesture for two directions.

UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];
leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;

UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeAction:)];
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;


UIView *temp = [[UIView alloc]initWithFrame:self.view.frame];

temp.backgroundColor = [UIColor clearColor];
[temp addGestureRecognizer:leftSwipe];
[temp addGestureRecognizer:rightSwipe];

[self.view addSubview:temp];

Second, you never specified the direction of the gesture leaving it to default to right (or 1 on the direction enum)

From the documentation:

The default direction is UISwipeGestureRecognizerDirectionRight. See descriptions of UISwipeGestureRecognizerDirection constants for more information.

typedef enum {
   UISwipeGestureRecognizerDirectionRight = 1 << 0,
   UISwipeGestureRecognizerDirectionLeft  = 1 << 1,
   UISwipeGestureRecognizerDirectionUp    = 1 << 2,
   UISwipeGestureRecognizerDirectionDown  = 1 << 3
} UISwipeGestureRecognizerDirection;

Upvotes: 13

joeld
joeld

Reputation: 32954

swipe.direction sets the direction(s) you're recognizing, it doesn't tell you which direction was swiped. Add this line when creating your recognizer:

swipe.direction = UISwipeGestureRecognizerDirectionLeft|UISwipeGestureRecognizerDirectionRight;

If you need to detect which direction was swiped, just use two different Recognizers, one for left and one for right.

Upvotes: 1

Related Questions