UITapGestureRecognizer - make it work on touch down, not touch up? UITapGestureRecognizer - make it work on touch down, not touch up? ios ios

UITapGestureRecognizer - make it work on touch down, not touch up?


Use a UILongPressGestureRecognizer and set its minimumPressDuration to 0. It will act like a touch down during the UIGestureRecognizerStateBegan state.

For Swift 4+

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

For Objective-C

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


Create your custom TouchDownGestureRecognizer subclass and implement gesture in touchesBegan:

TouchDownGestureRecognizer.h

#import <UIKit/UIKit.h>@interface TouchDownGestureRecognizer : UIGestureRecognizer@end

TouchDownGestureRecognizer.m

#import "TouchDownGestureRecognizer.h"#import <UIKit/UIGestureRecognizerSubclass.h>@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

implementation:

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

Swift implementation:

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

Here is the Swift syntax for 2017 to paste:

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

Note that this is a drop-in replacement for UITap. So in code like...

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

you can safely swap to....

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

Testing shows it will not be called more than once. It works as a drop-in replacement; you can just swap between the two calls.


Swift (without subclassing)

Here is a Swift version similar to Rob Caraway's Objective-C answer.

The idea is to use a long press gesture recognizer with the minimumPressDuration set to zero rather than using a tap gesture recognizer. This is because the long press gesture recognizer reports touch began events while the tap gesture does not.

import UIKitclass 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")        }    }}