web-dev-qa-db-fra.com

UITapGestureRecognizer - permet-il de travailler au toucher et non à la retouche?

Ce que j'utilise pour l'événement tap est très sensible au facteur temps, donc je suis curieux de savoir s'il est possible d'activer UITapGestureRecognizer lorsque l'utilisateur touche simplement au sol, au lieu de leur demander également de faire une retouche?

76
user212541

Créez votre sous-classe personnalisée TouchDownGestureRecognizer et implémentez le geste dans 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

la mise en oeuvre:

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

-(void)handleTouchDown:(TouchDownGestureRecognizer *)touchDown{
    NSLog(@"Down");
}

Mise en œuvre rapide:

import UIKit
import UIKit.UIGestureRecognizerSubclass

class 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
    }
}

Voici la syntaxe Swift pour 2017 à coller:

import UIKit.UIGestureRecognizerSubclass

class 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
    }
}

Notez qu'il s'agit d'un remplacement instantané de UITap. Donc, dans le code comme ...

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

vous pouvez échanger en toute sécurité pour ....

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

Les tests montrent qu'il ne sera pas appelé plus d'une fois. Cela fonctionne comme un remplacement immédiat; vous pouvez simplement permuter entre les deux appels.

126
LE SANG

Utilisez un UILongPressGestureRecognizer et définissez son minimumPressDuration sur 0. Il agira comme un toucher du sol pendant l’état UIGestureRecognizerStateBegan.

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

Pour Objective-C

Exemple:

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

Swift (sans sous-classement)

Voici une Swift similaire à réponse Objective-C de Rob Caraway .

L'idée est d'utiliser un identificateur de geste de pression longue avec le minimumPressDuration défini sur zéro plutôt que d'utiliser un identificateur de geste de tapotement. Cela est dû au fait que les rapports de reconnaissance des gestes de presse longs signalent que les contacts ont commencé des événements, contrairement au geste de toucher.

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")
        }
    }
}
21
Suragch

C'est une autre solution. Créer une sous-classe de UIControl. Vous pouvez l'utiliser comme UIView même dans Storyboard, car UIControl est une sous-classe d'UIView.

class TouchHandlingView: UIControl {
}

Et ajoutez-y la cible:

@IBOutlet weak var mainView: TouchHandlingView!
...

mainView.addTarget(self, action: "startAction:", forControlEvents: .TouchDown)
...

Ensuite, l'action désignée s'appellera comme UIButton:

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