2011-03-03 12 views
54

Ok, he estado buscando casi todas las opciones bajo el sol para capturar gestos multitáctiles, y finalmente he completado el ciclo y estoy de regreso en UIPanGestureRecognizer.¿Cómo puedo capturar qué dirección se panoramiza utilizando UIPanGestureRecognizer?

La funcionalidad que quiero es realmente bastante simple. Configuré un gesto con dos dedos y quiero poder desplazarme por algunas imágenes según la cantidad de píxeles que mueva. Tengo todo lo que funcionó bien, pero quiero ser capaz de capturar si el gesto de panorámica es INVERTIDO.

¿Hay una forma integrada que no veo para detectar volver atrás en un gesto? ¿Tendría que almacenar mi punto de partida original, luego seguir el punto final, luego ver dónde se mueven después de eso y se si es menor que el punto final inicial y luego retroceder en consecuencia? Puedo ver que funciona, ¡pero espero que haya una solución más elegante!

Gracias

EDIT:

Aquí es el método que el reconocedor está configurado para disparar. Es un poco de un truco, pero funciona:

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

He llegado sólo hasta el punto en que voy a empezar a tratar de realizar un seguimiento de las diferencias entre los valores ... para tratar de decir de qué manera están panoramización

+0

Se puede publicar la aplicación del método que su pan incendios gesto reconocedor? –

Respuesta

161

En UIPanGestureRecognizer puede utilizar -velocityInView: para obtener la velocidad de los dedos en el momento en que se reconoció el gesto.

Si quería hacer una cosa en un derecho de la cacerola y una cosa en una cacerola de la izquierda, por ejemplo, usted podría hacer algo como:

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

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

Si literalmente quiere detectar una inversión, como en desea comparar una nueva velocidad a un viejo uno y ver si es sólo en la dirección opuesta - cualquier dirección que puede ser - que podría hacer:

// 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; 
} 

el multiplican y se agrega lo que puede parecer un poco extraño. En realidad es un producto escalar, pero puede estar seguro de que será un número positivo si los gestos van en la misma dirección, bajando a 0 si están exactamente en ángulo recto y luego convirtiéndose en un número negativo si están en el lado opuesto dirección.

+0

¡Guau! Muy por encima del llamado del deber. ¡Esa respuesta es exactamente lo que necesitaba! Gracias Tommmy! –

+0

¡Justo lo que estaba buscando! ¡Gracias! :) – Amit

+0

¡Gran parte del código! –

7

Aquí es una forma fácil de detectar antes de que comience el reconocedor gesto:

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 
} 

Si desea una única arrastre vertical, se puede conmutar el x y y.

4

Este código de Serghei Catraniuc funcionó mejor para mí. 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 
     } 


    } 
} 

// Extensiones

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 
     } 
    } 
} 
Cuestiones relacionadas