Is there anyway to expedite it, or is it just that the processing of the gesture to determine whether it's a tap is intensive and is impossible to shorten?
The delay seems to be dependent on how long it takes to process the gesture, so yes, it is not possible to adjust it (you can log -touchesBegan:withEvent:
to see exactly when it is called). For example, if you touch a UIView
with a UITapGestureRecognizer
and don't move your finger, the tap recognizer still thinks there's a chance you'll lift your finger in that same position, which will be recognized as a tap. So it will keep waiting until you have panned your finger or lifted it. On the other hand if you pan immediately, the UIView gets sent -touchesBegan:withEvent:
with almost no delay.
Workarounds that you could try are:
Use the gesture recognizer's cancelTouchesInView
property instead. If you set this to YES
the UIView
will then process touches right away, and then if the gesture recognizer ends up recognizing the touches as a gesture, the view gets sent -touchesCancelled:withEvent:
, where you can roll back any changes you made.
Use cancelTouchesInView
with an NSTimer
in the UIView
. Start the NSTimer
in the UIView
's -touchesBegan:withEvent:
and when it fires, perform your action on the view. If the view gets sent -touchesCancelled:withEvent:
before the timer fires, cancel the timer.
Subclass UIGestureRecognizer
and implement your own tap recognizer :)
I've made an example of options 1 and 2. The example has a view which you can drag around the screen, and the view has a tap recognizer that changes the color of the view. If you tap the view but drag it a little before releasing, you'll see the 'roll back' snapping the view to its position before the touch. If you set the JCPanningView
's delayResponseToTouch
to YES
, you don't see any dragging within the delay period.
This may or may not work for you depending on how your UIView
s are handling their touches.
Here is the view controller's interface (JCGestureViewController.h
):
#import <UIKit/UIKit.h>
@interface JCGestureViewController : UIViewController
@end
@interface JCPanningView : UIView
@property (nonatomic) BOOL delayResponseToTouch;
- (void)changeColor;
@end
and implementation (JCGestureViewController.m
):
#import "JCGestureViewController.h"
@interface JCGestureViewController ()
@property (strong, nonatomic) JCPanningView *panningView;
@end
@implementation JCGestureViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_panningView = [[JCPanningView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 200.0f)];
[self.view addSubview:_panningView];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(tappedPanningView)];
tapRecognizer.cancelsTouchesInView = YES;
[_panningView addGestureRecognizer:tapRecognizer];
// set this to YES to have a timer delay the view's response to touches
_panningView.delayResponseToTouch = NO;
}
- (void)tappedPanningView
{
[self.panningView changeColor];
}
@end
@interface JCPanningView ()
@property (nonatomic) CGPoint touchBeganLocation;
@property (nonatomic) CGPoint centerWhenTouchBegan;
@property (nonatomic) BOOL respondToTouches;
@property (nonatomic) NSTimer *timer;
@end
@implementation JCPanningView
- (void)dealloc
{
if (_timer) {
[_timer invalidate];
_timer = nil;
}
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [self randomColor];
}
return self;
}
- (void)changeColor
{
self.backgroundColor = [self randomColor];
}
- (CGFloat)randomRGBValue
{
return (arc4random() % 255) / 255.0f;
}
- (UIColor *)randomColor
{
return [UIColor colorWithRed:[self randomRGBValue] green:[self randomRGBValue] blue:[self randomRGBValue] alpha:1.0f];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"touchesBegan:");
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
self.touchBeganLocation = [touch locationInView:self.superview];
self.centerWhenTouchBegan = self.center;
if (self.delayResponseToTouch) {
if (self.timer) {
[self.timer invalidate];
}
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.2
target:self
selector:@selector(startRespondingToTouches)
userInfo:nil
repeats:NO];
}
}
- (void)startRespondingToTouches
{
self.respondToTouches = YES;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
self.center = self.centerWhenTouchBegan;
if (self.timer) {
[self.timer invalidate];
self.timer = nil;
}
if (self.delayResponseToTouch) {
self.respondToTouches = NO;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
if (self.delayResponseToTouch && !self.respondToTouches) {
return;
}
UITouch *touch = [touches anyObject];
CGPoint newLocation = [touch locationInView:self.superview];
CGPoint delta = CGPointMake(newLocation.x - self.touchBeganLocation.x, newLocation.y - self.touchBeganLocation.y);
self.center = CGPointMake(self.centerWhenTouchBegan.x + delta.x, self.centerWhenTouchBegan.y + delta.y);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.delayResponseToTouch) {
self.respondToTouches = NO;
}
}
@end
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
) – Olette