我试图在我的 ViewController(它有一个 tableView)中实现两个必须一个接一个工作的手势识别器。第一个是向下滑动手势,第二个是长按手势。
这是我根据@sergio 的建议修改的代码
- (void)viewDidLoad
{
[super viewDidLoad];
swipeDown = [[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeDownAction)] autorelease];
longPress = [[[CustomLongPress alloc]initWithTarget:self action:@selector(longPressAction)] autorelease];
longPress.minimumPressDuration = 2;
swipeDown.numberOfTouchesRequired = 1;
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
swipeDown.delegate = self ;
longPress.delegate = self ;
[myTableView addGestureRecognizer:swipeDown];
[myTableView addGestureRecognizer:longPress];
}
-(void)swipeDownAction {
_methodHasBeenCalled = YES; // bool @property declared in .h
NSLog(@"Swipe down detected");
}
-(void)longPressAction {
NSLog(@"long press detected");
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
还有我的 UILongPressGestureRecognizer 子类:
#import "CustomLongPress.h"
#import "ViewController.h"
@interface CustomLongPress()
{
ViewController *vc;
}
@end
@implementation CustomLongPress
-(id)initWithTarget:(id)target action:(SEL)action controller:(ViewController *)viewCon
{
self = [super initWithTarget:target action:action];
if (self) {
vc = viewCon;
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(vc.methodHasBeenCalled ? @"Yes" : @"No");
if (vc.methodHasBeenCalled) {
[super touchesBegan:touches withEvent:event];
}
}
不幸的是,我仍然只从 swipeDown 获得日志,但没有关于 longPress 的日志
最佳答案
为此,您需要创建自己的自定义手势识别器。最好的方法是将 UILongPressGestureRecognizer
子类化并使其仅在滑动结束后才“接受”长按。例如,在 touchesBegan
中方法
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
<if swipe recognizer action method has been called>
[super touchesBegan:touches withEvent:event];
}
}
这样,两个手势识别器都会尝试识别手势:滑动识别器会立即识别;而自定义识别器将“等待”滑动识别器被触发。
实现条件的简单方法 <if swipe recognizer action method has been called>
将在您的滑动操作中设置一个全局标志(您在执行滑动操作时设置它;然后自定义识别器读取它的值)。这很简单,但目前还不是您能找到的最佳实现方式。
另一种方法是依赖 requiresGestureRecognizerToFail
链接 3 个标准手势识别器,我们称它们为 A、B 和 C,其中:
- A 是
UISwipeGestureRecognizer
; - C 是
UILongPressGestureRecognizer
; - B 是任何手势识别器。
您可以这样配置它们:
C --> B --> A
特此x --> y
表示x
需要 y
失败。因此,您将拥有 C
(您的长按手势识别器)将需要 B
GR 失败和 B
需要 A
(您的滑动识别器)失败; B
一旦 A
就会失败将识别滑动;一次B
失败,C
将允许识别长按(如果有)。
编辑:
阅读您的评论后,您是否介意尝试一下,看看是否有帮助:
删除你覆盖的
touchesBegan
并将其替换为:- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { }
然后定义:
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { if (vc.methodHasBeenCalled) { [super touchesBegan:touches withEvent:event]; } else { return; } }
如果这不起作用,则让您的自定义手势识别器继承自通用手势识别器并
离开
touchesBegan:
到位并更换touchesMoved
与:- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { self.lastTouch = [touches anyObject]; if (vc.methodHasBeenCalled && self.gestureNotBegunYet == YES) { self.gestureNotBegunYet = NO; [self performSelector:@selector(recognizeLongPress) withObject:nil afterDelay:1.0]; } else { return; } }
并添加:
- (float)travelledDistance {
CGPoint currentLocation = [self.lastTouch locationInView:self.view.superview];
return sqrt(pow((currentLocation.x - self.initialLocation.x), 2.0) +
pow((currentLocation.y - self.initialLocation.y), 2.0));
}
- (void)fail {
self.gestureNotBegunYet = YES;
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
- (void)recognizeLongPress {
if ([self travelledDistance] < kTapDragThreshold) {
self.longPressed = YES;
self.state = UIGestureRecognizerStateChanged;
} else {
[self fail];
self.state = UIGestureRecognizerStateFailed;
}
}
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
[self fail];
[super touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
[self fail];
[super touchesCancelled:touches withEvent:event];
}
您需要在 .h
中定义
@property(nonatomic) CGPoint initialLocation;
@property(nonatomic, retain) UITouch* lastTouch;
@property(nonatomic) BOOL gestureNotBegunYet;
关于ios - 结合向下滑动和长按,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13726705/