2012-10-30 5 views
6

Die allowableMovement Eigenschaft in meinem UILongPressGestureRecognizer scheint ignoriert zu werden. Ich erstellte ein neues Projekt (Xcode 4.5.1, iOS 6) mit der Vorlage "Einzelansicht-Anwendung" und fügte der Ansicht einen Langdruck-Gestenerkenner hinzu. Es gibt eine Steckdose und eine Aktion. Hier ist der Code für die Aktion-Methode:allowedMovement scheint ignoriert zu werden

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

Wenn ich lange genug drücken und loslassen bekomme ich diese im Protokoll:

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 

Dies ist, was ich erwarten würde.

Aber egal was ich allowableMovement auf (positiv, negativ, groß, klein), sobald der Zustand UIGestureRecognizerStateBegan ist, kann ich meinen Finger über den ganzen Bildschirm ziehen. Der Status ändert sich in UIGestureRecognizerStateChanged und es gibt häufige Updates und locationInView wird weiterhin genau verfolgt. Wenn ich loslasse, bekomme ich den UIGestureRecognizerStateRecognized Zustand und eine endgültige Ausgabe zum Log.

Die Klassenreferenz besagt, dass der Erkenner fehlschlagen sollte, wenn die Bewegung allowableMovement überschreitet. Warum scheint die allowableMovement Eigenschaft ignoriert zu werden?

Antwort

23

Die allowableMovement Eigenschaft ist nicht darüber, wie weit Sie ziehen können, nachdem die Geste gestartet wurde. Es geht darum, wie weit Sie sich bewegen können, bevor die Geste beginnt.

Aus der Klasse Referenz:

Die Geste beginnt (UIGestureRecognizerStateBegan), wenn die Anzahl der zulässigen Finger (numberOfTouchesRequired) wurden für den angegebenen Zeitraum (minimumPressDuration) und die Berührungen bewegen sich nicht über den zulässigen Bereich gedrückt der Bewegung (zulässige Bewegung).

Dies wird deutlich, wenn man minimumPressDuration etwas hoch wie 3 Sekunden und allowableMovement etwas niedrig wie 1 Pixel eingestellt. Wenn dein Finger überhaupt rollt, wird die Geste nicht beginnen. Aber wenn Sie allowableMovement auf 100 setzen, kann Ihr Finger ziemlich viel rollen und die Geste wird beginnen.

Auf diese Weise ist es wie die anderen Eigenschaften. Sie handeln von dem, was für den Start der Geste erforderlich ist.

+0

@ Murray Sagal: Dies löste meine Verwirrung auch. Fragen Sie sich, ob es eine Möglichkeit gibt zu erkennen, ob der Benutzer nach dem Start von LongPressGesture den Finger aus der Ansicht zieht. – Kashif

+0

@TPos Ich denke, Sie können 'locationInView:' oder eine der Methoden wie es verwenden. Aber es klingt, als wäre es seiner eigenen Frage würdig. –

4

Ich dachte, allowableMovement hatte genau diesen Zweck. Ich machte eine kleine Unterklasse, um das "erwartete" Verhalten mit einem allowableMovementAfterBegan zu implementieren.

#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

Interessant. Was ist Ihr Anwendungsfall für die Begrenzung der zulässigen Bewegung? –

+0

Ich habe es benutzt, um lange auf Inhalte in einem UIScrollView zu drücken. – duemunk

+0

Gerade in den Fall, auf den Sie sich beziehen, haben Sie eine UICollectionViewCell, der ich eine Gestenerkennung hinzufügen möchte, aber die Geste abbrechen, wenn der Benutzer die UICollectionView vertikal scrollt (so funktioniert UITableView standardmäßig). Es war auch überraschend für mich, dass die erlaubte Bewegung das auch nicht bedeutet, aber das scheint eine großartige Lösung zu sein, danke! –