How can I capture which direction is being panned using UIPanGestureRecognizer?

和自甴很熟 提交于 2019-12-04 07:39:52

问题


Ok so I have been looking around at just about every option under the sun for capturing multi-touch gestures, and I have finally come full circle and am back at the UIPanGestureRecognizer.

The functionality I want is really quite simple. I have setup a two finger pan gesture, and I want to be able to shuffle through some images depending on how many pixels I move. I have all that worked out okay, but I want to be able to capture if the pan gesture is REVERSED.

Is there a built in way that I'm just not seeing to detect going back on a gesture? Would I have to store my original starting point, then track the end point, then see where they move after that and se if its less than the initial ending point and then reverse accordingly? I can see that working, but I'm hoping there is a more elegant solution!!

Thanks

EDIT:

Here is the method that the recognizer is set to fire. Its a bit of a hack, but it works:

-(void) throttle:(UIGestureRecognizer *) recognize{

throttleCounter ++;

if(throttleCounter == 6){
    throttleCounter = 0;
    [self nextPic:nil];
}

UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *) recognize;
UIView *view = recognize.view;
if(panGesture.state == UIGestureRecognizerStateBegan){
    CGPoint translation = [panGesture translationInView:view.superview];
    NSLog(@"X: %f, Y:%f", translation.x, translation.y);
}else if(panGesture.state == UIGestureRecognizerStateEnded){
    CGPoint translation = [panGesture translationInView:view.superview];
            NSLog(@"X: %f, Y:%f", translation.x, translation.y);
}
  }

I've just gotten to the point where I am going to start trying to track the differences between values...to try and tell which way they are panning


回答1:


On UIPanGestureRecognizer you can use -velocityInView: to get the velocity of the fingers at the time that gesture was recognised.

If you wanted to do one thing on a pan right and one thing on a pan left, for example, you could do something like:

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

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

If you literally want to detect a reversal, as in you want to compare a new velocity to an old one and see if it is just in the opposite direction — whichever direction that may be — you could do:

// assuming lastGestureVelocity is a class variable...

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

    if(velocity.x*lastGestureVelocity.x + velocity.y*lastGestureVelocity.y > 0)
    {
        NSLog(@"gesture went in the same direction");
    }
    else
    {
        NSLog(@"gesture went in the opposite direction");
    }

    lastGestureVelocity = velocity;
}

The multiply and add thing may look a little odd. It's actually a dot product, but rest assured it'll be a positive number if the gestures are in the same direction, going down to 0 if they're exactly at right angles and then becoming a negative number if they're in the opposite direction.




回答2:


Here's an easy to detect before the gesture recognizer begins:

public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    guard let panRecognizer = gestureRecognizer as? UIPanGestureRecognizer else {
        return super.gestureRecognizerShouldBegin(gestureRecognizer)
    }

    // Ensure it's a horizontal drag
    let velocity = panRecognizer.velocity(in: self)
    if abs(velocity.y) > abs(velocity.x) {
        return false
    }
    return true
}

If you want a vertical only drag, you can switch the x and y.




回答3:


This code from Serghei Catraniuc worked out better for me. https://github.com/serp1412/LazyTransitions

     func addPanGestureRecognizers() {
       let panGesture = UIPanGestureRecognizer(target: self, action: #selector(respondToSwipeGesture(gesture:)))
        self.view.addGestureRecognizer(panGesture)
     }

     func respondToSwipeGesture(gesture: UIGestureRecognizer){
        if let swipeGesture = gesture as? UIPanGestureRecognizer{

        switch gesture.state {
        case .began:
            print("began")

        case .ended:
             print("ended")
             switch swipeGesture.direction{
             case .rightToLeft:
                print("rightToLeft")
             case .leftToRight:
                print("leftToRight")
             case .topToBottom:
                print("topToBottom")
             case .bottomToTop:
                print("bottomToTop")
             default:
                print("default")
            }

        default: break
        }


    }
}

// Extensions

import Foundation
import UIKit

public enum UIPanGestureRecognizerDirection {
    case undefined
    case bottomToTop
    case topToBottom
    case rightToLeft
    case leftToRight
}
public enum TransitionOrientation {
    case unknown
    case topToBottom
    case bottomToTop
    case leftToRight
    case rightToLeft
}


extension UIPanGestureRecognizer {
    public var direction: UIPanGestureRecognizerDirection {
        let velocity = self.velocity(in: view)
        let isVertical = fabs(velocity.y) > fabs(velocity.x)

        var direction: UIPanGestureRecognizerDirection

        if isVertical {
            direction = velocity.y > 0 ? .topToBottom : .bottomToTop
        } else {
            direction = velocity.x > 0 ? .leftToRight : .rightToLeft
        }

        return direction
    }

    public func isQuickSwipe(for orientation: TransitionOrientation) -> Bool {
        let velocity = self.velocity(in: view)
        return isQuickSwipeForVelocity(velocity, for: orientation)
    }

    private func isQuickSwipeForVelocity(_ velocity: CGPoint, for orientation: TransitionOrientation) -> Bool {
        switch orientation {
        case .unknown : return false
        case .topToBottom : return velocity.y > 1000
        case .bottomToTop : return velocity.y < -1000
        case .leftToRight : return velocity.x > 1000
        case .rightToLeft : return velocity.x < -1000
        }
    }
}

extension UIPanGestureRecognizer {
    typealias GestureHandlingTuple = (gesture: UIPanGestureRecognizer? , handle: (UIPanGestureRecognizer) -> ())
    fileprivate static var handlers = [GestureHandlingTuple]()

    public convenience init(gestureHandle: @escaping (UIPanGestureRecognizer) -> ()) {
        self.init()
        UIPanGestureRecognizer.cleanup()
        set(gestureHandle: gestureHandle)
    }

    public func set(gestureHandle: @escaping (UIPanGestureRecognizer) -> ()) {
        weak var weakSelf = self
        let tuple = (weakSelf, gestureHandle)
        UIPanGestureRecognizer.handlers.append(tuple)
        addTarget(self, action: #selector(handleGesture))
    }

    fileprivate static func cleanup() {
        handlers = handlers.filter { $0.0?.view != nil }
    }

    @objc private func handleGesture(_ gesture: UIPanGestureRecognizer) {
        let handleTuples = UIPanGestureRecognizer.handlers.filter{ $0.gesture === self }
        handleTuples.forEach { $0.handle(gesture)}
    }
}

extension UIPanGestureRecognizerDirection {
    public var orientation: TransitionOrientation {
        switch self {
        case .rightToLeft: return .rightToLeft
        case .leftToRight: return .leftToRight
        case .bottomToTop: return .bottomToTop
        case .topToBottom: return .topToBottom
        default: return .unknown
        }
    }
}

extension UIPanGestureRecognizerDirection {
    public var isHorizontal: Bool {
        switch self {
        case .rightToLeft, .leftToRight:
            return true
        default:
            return false
        }
    }
}


来源:https://stackoverflow.com/questions/5187502/how-can-i-capture-which-direction-is-being-panned-using-uipangesturerecognizer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!