UITapGestureRecognizer: ¿funciona en Touchdown, no Touch Up?

Para lo que estoy usando el evento tap es muy sensible al tiempo, entonces tengo curiosidad si es posible hacer que UITapGestureRecognizer se active cuando el usuario simplemente toca hacia abajo, en lugar de requerir que también lo retoque.

Cree su subclase TouchDownGestureRecognizer personalizada e implemente el gesto en touchesBegan:

TouchDownGestureRecognizer.h

#import  @interface TouchDownGestureRecognizer : UIGestureRecognizer @end 

TouchDownGestureRecognizer.m

 #import "TouchDownGestureRecognizer.h" #import  @implementation TouchDownGestureRecognizer -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ if (self.state == UIGestureRecognizerStatePossible) { self.state = UIGestureRecognizerStateRecognized; } } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ self.state = UIGestureRecognizerStateFailed; } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ self.state = UIGestureRecognizerStateFailed; } @end 

implementación:

 #import "TouchDownGestureRecognizer.h" TouchDownGestureRecognizer *touchDown = [[TouchDownGestureRecognizer alloc] initWithTarget:self action:@selector(handleTouchDown:)]; [yourView addGestureRecognizer:touchDown]; -(void)handleTouchDown:(TouchDownGestureRecognizer *)touchDown{ NSLog(@"Down"); } 

Implementación rápida:

 import UIKit import UIKit.UIGestureRecognizerSubclass class TouchDownGestureRecognizer: UIGestureRecognizer { override func touchesBegan(touches: Set, withEvent event: UIEvent) { if self.state == .Possible { self.state = .Recognized } } override func touchesMoved(touches: Set, withEvent event: UIEvent) { self.state = .Failed } override func touchesEnded(touches: Set, withEvent event: UIEvent) { self.state = .Failed } } 

Aquí está la syntax de Swift para 2017:

 import UIKit.UIGestureRecognizerSubclass class SingleTouchDownGestureRecognizer: UIGestureRecognizer { override func touchesBegan(_ touches: Set, with event: UIEvent) { if self.state == .possible { self.state = .recognized } } override func touchesMoved(_ touches: Set, with event: UIEvent) { self.state = .failed } override func touchesEnded(_ touches: Set, with event: UIEvent) { self.state = .failed } } 

Tenga en cuenta que este es un reemplazo UITap para UITap . Entonces en código como …

 func add(tap v:UIView, _ action:Selector) { let t = UITapGestureRecognizer(target: self, action: action) v.addGestureRecognizer(t) } 

puedes cambiar de forma segura a ….

 func add(hairtriggerTap v:UIView, _ action:Selector) { let t = SingleTouchDownGestureRecognizer(target: self, action: action) v.addGestureRecognizer(t) } 

Las pruebas muestran que no se llamará más de una vez. Funciona como un reemplazo directo; puedes simplemente intercambiar entre las dos llamadas.

Use un UILongPressGestureRecognizer y establezca su minimumPressDuration en 0. Actuará como un toque hacia abajo durante el estado UIGestureRecognizerStateBegan .

Para Swift 4

 func setupTap() { let touchDown = UILongPressGestureRecognizer(target:self, action: #selector(didTouchDown)) touchDown.minimumPressDuration = 0 view.addGestureRecognizer(touchDown) } func didTouchDown(gesture: UILongPressGestureRecognizer) { if (gesture.state == .began){ doSomething() } } 

Para Objective-C

Ejemplo:

 -(void)setupLongPress { self.longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(didLongPress:)]; self.longPress.minimumPressDuration = 0; [self.view addGestureRecognizer:self.longPress]; } -(void)didLongPress:(UILongPressGestureRecognizer *)gesture { if (gesture.state == UIGestureRecognizerStateBegan){ [self doSomething]; } } 

Swift (sin subclases)

Aquí hay una versión Swift similar a la respuesta Objective-C de Rob Caraway .

La idea es usar un reconocedor de gestos de pulsación larga con la configuración minimumPressDuration puesta a cero en lugar de usar un reconocedor de gestos de toque. Esto se debe a que el reconocedor de gestos de pulsación larga informa que los eventos táctiles comienzan mientras que el gesto de tap no.

 import UIKit class ViewController: UIViewController { @IBOutlet weak var myView: UIView! override func viewDidLoad() { super.viewDidLoad() // Add "long" press gesture recognizer let tap = UILongPressGestureRecognizer(target: self, action: #selector(tapHandler)) tap.minimumPressDuration = 0 myView.addGestureRecognizer(tap) } // called by gesture recognizer @objc func tapHandler(gesture: UITapGestureRecognizer) { // handle touch down and touch up events separately if gesture.state == .began { // do something... print("tap down") } else if gesture.state == .ended { // optional for touch up event catching // do something else... print("tap up") } } } 

Esta es otra solución. Crear la subclase de UIControl. Puedes usarlo como UIView incluso en Storyboard porque UIControl es la subclase de UIView.

 class TouchHandlingView: UIControl { } 

Y agregaTarget to it:

 @IBOutlet weak var mainView: TouchHandlingView! ... mainView.addTarget(self, action: "startAction:", forControlEvents: .TouchDown) ... 

Entonces la acción designada se llamará como UIButton:

 func startAction(sender: AnyObject) { print("start") }