The allowableMovement
property in my UILongPressGestureRecognizer
seems to be ignored. I created a new project (Xcode 4.5.1, iOS 6) using the Single View Application template and added a Long Press Gesture Recognizer to the view. There's an outlet wired up and an action. Here's the code for the action method:
- (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);
}
If I press long enough and let go I get this in the log:
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
This is what I would expect.
But no matter what I set allowableMovement
to (positive, negative, big, small), once the state is UIGestureRecognizerStateBegan
, I can drag my finger all over the screen. The state changes to UIGestureRecognizerStateChanged
and there are frequent updates and locationInView continues to accurately track. When I let go I get the UIGestureRecognizerStateRecognized
state and a final output to the log.
The class reference says that the recognizer should fail if movement exceeds allowableMovement
. Why does the allowableMovement
property seem to be ignored?
The allowableMovement
property is not about how far you can drag after the gesture has started. It is about how far you can move before the gesture starts.
From the class reference:
The gesture begins (UIGestureRecognizerStateBegan) when the number of allowable fingers (numberOfTouchesRequired) have been pressed for the specified period (minimumPressDuration) and the touches do not move beyond the allowable range of movement (allowableMovement).
This becomes apparent when you set minimumPressDuration
to something high like 3 seconds and allowableMovement
to something low like 1 pixel. If your finger rolls at all the gesture won't begin. But if you set allowableMovement
to 100 your finger can roll around quite a bit and the gesture will start.
In this way it is like the other properties. They are all about what is required for the gesture to start.
I thought allowableMovement
had exactly that purpose. I made a small subclass to implement the "expected" behavior with a 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;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With