web-dev-qa-db-fra.com

iOS: Comment obtenir la durée d'un geste long?

Je travaille sur un jeu dans lequel un attribut d'un objet de jeu est défini en appuyant longuement sur l'objet lui-même. La valeur de l'attribut est déterminée par la durée du geste long. J'utilise UILongPressGestureRecognizer à cette fin, c'est donc quelque chose comme ceci:

[gameObjectView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] 
                                       initWithTarget:self action:@selector(handle:)]];

Puis la fonction de gestionnaire

- (void)handle:(UILongPressGestureRecognizer)gesture {
  if (gesture.state == UIGestureRecognizerStateEnded) {
    // Get the duration of the gesture and calculate the value for the attribute
  }
}

Comment puis-je obtenir la durée du geste de pression long dans ce cas?

16
Ryan Dao

Je suis à peu près sûr que le geste ne stocke pas ces informations pour que vous puissiez y accéder. Vous pouvez uniquement y définir une propriété appelée minimumPressDuration, c'est-à-dire le temps nécessaire pour que le geste soit reconnu.

Solution de contournement avec ios 5 (non testée):

Créez une propriété NSTimer appelée timer: @property (nonatomic, strong) NSTimer *timer;

Et un compteur: @property (nonatomic, strong) int counter;

Alors @synthesize

- (void)incrementCounter {
    self.counter++;
}

- (void)handle:(UILongPressGestureRecognizer)gesture {
    if (gesture.state == UIGestureRecognizerStateBegan) {
         self.counter = 0;
         self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(incrementCounter) userInfo:nil repeats:yes];
    }
    if (gesture.state == UIGestureRecognizerStateEnded) {
        [self.timer invalidate];
    }
}

Ainsi, lorsque le geste commence, lancez une minuterie qui déclenche la méthode d'incrémentation toutes les secondes jusqu'à la fin du geste. Dans ce cas, vous voudrez régler la minimumPressDuration à 0, sinon le geste ne commencera pas tout de suite. Alors fais ce que tu veux avec le compteur!

27
Rupert Horlick

Aucune minuterie nécessaire. Vous pouvez y arriver de cette façon:

- (void)handleRecognizer:(UILongPressGestureRecognizer *)gesture
{
    static NSTimeInterval pressStartTime = 0.0; //This an be moved out and be kept as a property

    switch ([gesture state])
    {
        case UIGestureRecognizerStateBegan:
            //Keeping start time...
            pressStartTime = [NSDate timeIntervalSinceReferenceDate];
            break; /* edit*/
        case UIGestureRecognizerStateEnded:
        {
            //Calculating duration
            NSTimeInterval duration = [NSDate timeIntervalSinceReferenceDate] - pressStartTime;
            //Note that NSTimeInterval is a double value...
            NSLog(@"Duration : %f",duration);
            break;
        }
        default:
            break;
    }
}

De même, n'oubliez pas de définir la variable minimumPressDuration de l'outil de reconnaissance de mouvements sur 0 lors de sa création, si vous souhaitez obtenir la durée réelle de l'appui long:
myLongPressGestureRecognizer.minimumPressDuration = 0

8
Just Shadow

Il semble que de loin la solution la plus simple et la plus propre dans Cocoa Touch orienté objet consiste à sous-classer UILongPressGesture. Voici un exemple écrit en Swift. 

    class MyLongPressGesture : UILongPressGestureRecognizer {
        var startTime : NSDate?
    }

    func installGestureHandler() {
            let longPress = MyLongPressGesture(target: self, action: "longPress:")
            button.addGestureRecognizer(longPress)
    }

    @IBAction func longPress(gesture: MyLongPressGesture) {
            if gesture.state == .Began {
                    gesture.startTime = NSDate()
            }
            else if gesture.state == .Ended {
                    let duration = NSDate().timeIntervalSinceDate(gesture.startTime!)
                    println("duration was \(duration) seconds")
            }
    }

Si vous souhaitez inclure le temps écoulé depuis le premier tapotement, vous pouvez l’inclure dans le calcul de la durée en rajoutant gesture.minimumPressDuration. L'inconvénient est qu'il n'est probablement pas précis en micro-seconde, étant donné qu'il reste probablement un temps (minuscule) entre le déclenchement du geste et l'appel de votre gestionnaire .Start. Mais pour la grande majorité des applications, cela ne devrait pas avoir d'importance.

5
SafeFastExpressive

Voir la propriété "minimumPressDuration". Selon la documentation:

La période minimum de doigts doit appuyer sur la vue pour que le geste de Soit reconnu.

[...]

L'intervalle de temps est en secondes. La durée par défaut est de 0,5 Secondes.

4
fbernardo

Vous pouvez l'obtenir en suivant Swift 3.0

Logique: Assigne simplement l'heure de la presse et trouve la différence d'heure à laquelle le toucher se termine

Code:

//variable to calculate the press time
static var pressStartTime: TimeInterval = 0.0

func handleRecognizer(gesture: UILongPressGestureRecognizer) -> Double {
    var duration: TimeInterval = 0

    switch (gesture.state) {
    case .began:
        //Keeping start time...
        Browser.pressStartTime = NSDate.timeIntervalSinceReferenceDate

    case .ended:
        //Calculating duration
        duration = NSDate.timeIntervalSinceReferenceDate - Browser.pressStartTime
        //Note that NSTimeInterval is a double value...
        print("Duration : \(duration)")

    default:
        break;
    }

    return duration
}
1
Janmenjaya

Je sais que c'est une réponse tardive, mais cela fonctionne parfaitement pour moi dans IOS 7 & 8 sans avoir à créer de minuterie.

UILongPressGestureRecognizer *longGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(yourAction)]; // create the recognizer
longGR.minimumPressDuration = 10.0f; //Ten Seconds
longGR.allowableMovement = 50.0f; //Allowable Movement while being pressed
[gameObjectView setUserInteractionEnabled:YES]; //If setting interaction to a non-interactable object such as a UIImageView
[gameObjectView addGestureRecognizer:longGR]; //Add the gesture recognizer to your object
1
inVINCEable

Il semble qu'avec les nouvelles versions iOS (10 pour moi pour le moment), les rappels de reconnaissance de presse longs pour les états .begin et .ended se produisent l'un après l'autre, uniquement après la fin de l'événement, uniquement lorsque vous levez la main l'écran.

Cela fait la différence entre les deux événements soit des fractions de millisecondes, et non ce que vous cherchiez réellement.

En attendant que cela soit corrigé, j'ai décidé de créer un autre outil de reconnaissance des gestes à partir de zéro dans Swift, qui serait son squelette opérationnel.

import UIKit.UIGestureRecognizerSubclass
class LongPressDurationGestureRecognizer : UIGestureRecognizer {
        private var startTime : Date?
        private var _duration = 0.0
        public var duration : Double {
            get {
                return _duration
            }
        }
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
            startTime = Date() // now
            state = .begin
            //state = .possible, if you would like the recongnizer not to fire any callback until it has ended
        }
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
            _duration = Date().timeIntervalSince(self.startTime!)
            print("duration was \(duration) seconds")
            state = .ended
            //state = .recognized, if you would like the recongnizer not to fire any callback until it has ended
        }
 }

Ensuite, vous pouvez accéder facilement à la propriété .duration du LongPressDurationGestureRecognizer gesture reconnaître.

Par exemple:

func handleLongPressDuration(_ sender: LongPressDurationGestureRecognizer) {
        print(sender.duration)
}

Cet exemple spécifique ne prend pas en considération le nombre de contacts réellement effectués ou leur emplacement. Mais vous pouvez facilement jouer avec, en étendant le LongPressDurationGestureRecognizer.

0
Liron Berger