2012-10-30 6 views
6

La proprietà allowableMovement nel mio UILongPressGestureRecognizer sembra essere ignorata. Ho creato un nuovo progetto (Xcode 4.5.1, iOS 6) utilizzando il modello Applicazione vista singola e aggiunto un Riconoscitore di gesti a pressione lunga alla vista. C'è una presa cablata e un'azione. Ecco il codice per il metodo di azione:consentito Il movimento sembra essere ignorato

- (IBAction)longPress:(UILongPressGestureRecognizer *)sender 
{  
    if (sender.state == UIGestureRecognizerStatePossible) NSLog(@"possible"); 
    if (sender.state == UIGestureRecognizerStateBegan)  NSLog(@"began"); 
    if (sender.state == UIGestureRecognizerStateChanged) NSLog(@"changed");  
    if (sender.state == UIGestureRecognizerStateRecognized) NSLog(@"recognized");  
    if (sender.state == UIGestureRecognizerStateCancelled) NSLog(@"cancelled"); 
    if (sender.state == UIGestureRecognizerStateFailed)  NSLog(@"failed"); 

    CGPoint locationInView = [sender locationInView:self.view]; 

    NSLog(@"long press: allowableMovement= %f, x= %f, y= %f", sender.allowableMovement, locationInView.x, locationInView.y); 
} 

Se premo abbastanza a lungo e lasciare andare ottengo questo nel registro:

2012-10-30 20:24:41.449 Long Press[1078:907] began 
2012-10-30 20:24:41.455 Long Press[1078:907] long press: allowableMovement= 10.000000, x= 210.500000, y= 99.500000 
2012-10-30 20:24:42.880 Long Press[1078:907] recognized 
2012-10-30 20:24:42.882 Long Press[1078:907] long press: allowableMovement= 10.000000, x= 208.500000, y= 96.000000 

Questo è quello che mi aspetterei.

Ma non importa quello che ho impostato allowableMovement su (positivo, negativo, grande, piccolo), una volta che lo stato è UIGestureRecognizerStateBegan, posso trascinare il dito su tutto lo schermo. Lo stato cambia in UIGestureRecognizerStateChanged e ci sono aggiornamenti frequenti e locationInView continua a tracciare con precisione. Quando lascio andare, ottengo lo stato UIGestureRecognizerStateRecognized e un output finale nel log.

Il riferimento di classe indica che il riconoscimento deve fallire se il movimento supera allowableMovement. Perché la proprietà allowableMovement sembra essere ignorata?

risposta

23

La proprietà allowableMovement non riguarda la distanza che è possibile trascinare dopo l'inizio del gesto. Riguarda quanto lontano puoi muovere prima che inizi il gesto.

dal riferimento di classe:

Il gesto ha inizio (UIGestureRecognizerStateBegan) quando sono stati premuti il ​​numero di dita ammissibili (numberOfTouchesRequired) per il periodo specificato (minimumPressDuration) ei tocchi non andare oltre il campo ammissibile di movimento (movimento consentito).

Questo diventa evidente quando si imposta minimumPressDuration a qualcosa di alto come 3 secondi e allowableMovement a qualcosa di basso come 1 pixel. Se il tuo dito rotola, il gesto non inizierà. Ma se imposti il ​​valore da allowableMovement a 100 il tuo dito può rotolare un po 'e il gesto inizierà.

In questo modo è come le altre proprietà. Riguardano tutto ciò che è necessario affinché il gesto inizi.

+0

@ Murray Sagal: questo ha risolto anche la mia confusione. Chiedendosi, se c'è un modo per rilevare se l'utente trascina il dito fuori dalla vista dopo l'avvio di LongPressGesture. – Kashif

+0

@TPos Penso che tu possa usare 'locationInView:' o uno dei metodi come questo. Ma sembra che sarebbe degno della sua stessa domanda. –

4

Pensavo che lo allowableMovement avesse esattamente quello scopo. Ho creato una piccola sottoclasse per implementare il comportamento "previsto" con un allowableMovementAfterBegan.

#import <UIKit/UIKit.h> 
#import <UIKit/UIGestureRecognizerSubclass.h> 

@interface TDMLongPressGestureRecognizer : UILongPressGestureRecognizer 
@property (nonatomic, assign) CGFloat allowableMovementAfterBegan; 
@end 

@implementation TDMLongPressGestureRecognizer 
{ 
    CGPoint initialPoint; 
} 

- (instancetype)initWithTarget:(id)target action:(SEL)action 
{ 
    self = [super initWithTarget:target action:action]; 
    if (self) { 
     // Use default value for allowableMovement before touches begin 
     _allowableMovementAfterBegan = self.allowableMovement; 
    } 
    return self; 
} 

- (void)reset 
{ 
    [super reset];  
    initialPoint = CGPointZero; 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [super touchesBegan:touches withEvent:event]; 
    initialPoint = [self locationInView:self.view]; 
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [super touchesMoved:touches withEvent:event]; 

    if (!CGPointEqualToPoint(initialPoint, CGPointZero)) 
    { 
     CGPoint currentPoint = [self locationInView:self.view]; 

     CGFloat distance = hypot(initialPoint.x - currentPoint.x, initialPoint.y - currentPoint.y); 
     if (distance > self.allowableMovementAfterBegan) 
      self.state = UIGestureRecognizerStateFailed; 
     } 
    } 
} 
+0

Interessante. Qual è il tuo caso d'uso per limitare il movimento consentito? –

+0

L'ho usato per premere a lungo sui contenuti di un UIScrollView. – duemunk

+0

Ho appena eseguito il caso a cui ti stai riferendo: avere un UICollectionViewCell a cui vorrei aggiungere un riconoscimento di movimento, ma annullare il gesto se l'utente fa scorrere UICollectionView verticalmente (questo è il modo in cui UITableView funziona per impostazione predefinita). È stato anche sorprendente per me che AllowableMovement non intendesse questo, ma questa mi sembra un'ottima soluzione quindi grazie! –