马克,我遇到了同样的错误。如果你发布你的雷达#,我会在 bugreporter 中欺骗它。
我编写了以下解决方法。我将 UITapGestureRecognizer 子类化,然后使用子类来跟踪触发手势动作的触摸。如果我们在视图的 touchesEnded 中获得相同的触摸,我们将重定向到 touchesCancelled。 'immediateTarget' 是必需的,因为视图上的 touchesEnded 调用发生在手势的 touchesEnded 之后,但在调用手势的动作之前。
RPTapGestureRecognizer.h:
#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface RPTapGestureRecognizer : UITapGestureRecognizer
@property (nonatomic, retain) NSSet *lastTouches;
- (void)setImmediateTarget:(id)inTarget action:(SEL)inAction;
@end
RPTapGestureRecognizer.m:
#import "RPTapGestureRecognizer.h"
@interface RPTapGestureRecognizer ()
@property (nonatomic) SEL immediateAction;
@property (nonatomic, assign) id immediateTarget;
@end
@implementation RPTapGestureRecognizer
@synthesize lastTouches;
@synthesize immediateAction, immediateTarget;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.lastTouches = nil;
[super touchesBegan:touches withEvent:event];
}
- (void)setImmediateTarget:(id)inTarget action:(SEL)inAction
{
self.immediateTarget = inTarget;
self.immediateAction = inAction;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UIGestureRecognizerState startingState, finalState;
startingState = self.state;
[super touchesEnded:touches withEvent:event];
finalState = self.state;
if (startingState != finalState &&
finalState == UIGestureRecognizerStateEnded) {
/* Must copy; the underlying NSCFSet will be modified by the superclass, removing the touches */
self.lastTouches = [[touches copy] autorelease];
if (self.immediateAction)
[self.immediateTarget performSelector:self.immediateAction
withObject:self];
}
}
- (void)dealloc
{
self.lastTouches = nil;
self.immediateTarget = nil;
[super dealloc];
}
@end
在视图中:
@synthesize lastTapGesture
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.lastTapGesture && [self.lastTapGesture.lastTouches isEqualToSet:touches]) {
[self touchesCancelled:touches withEvent:event];
self.lastTapGesture = nil;
return;
}
/* touches ended implementation here */
}
- (void)willHandleMouseTapGesture:(RPTapGestureRecognizer *)tapGesture
{
/* Because one tap gesture is dependent upon another, the touchesEnded method is still going to be called, instead of touchesCanceled.
* This is an Apple bug against all versions of iOS at least up to 5.0. It will be called in the run loop before tapGesture's action is called.
*
* See http://stackoverflow.com/questions/6188997/how-to-cancel-button-tap-if-uigesturerecognizer-fires/6211922#6211922 for details.
*/
self.lastTapGesture = tapGesture;
}
- (void)configureGestures
{
/* Two finger taps */
RPTapGestureRecognizer *tapGestureOne;
tapGestureOne = [[[RPTapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleMouseTapGesture:)] autorelease];
tapGestureOne.numberOfTapsRequired = 1;
tapGestureOne.numberOfTouchesRequired = 2;
[tapGestureOne setImmediateTarget:self action:@selector(willHandleMouseTapGesture:)];
[self addGestureRecognizer:tapGestureOne];
[myGestures addObject:tapGestureOne];
RPTapGestureRecognizer *tapGestureTwo;
tapGestureTwo = [[[RPTapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleMouseTapGesture:)] autorelease];
tapGestureTwo.numberOfTapsRequired = 2;
tapGestureTwo.numberOfTouchesRequired = 2;
[tapGestureTwo setImmediateTarget:self action:@selector(willHandleMouseTapGesture:)];
[self addGestureRecognizer:tapGestureTwo];
}