问题描述
我试图在我的 ViewController(它有一个 tableView)中实现两个必须一个接一个工作的手势识别器.第一个是向下滑动手势,第二个是长按手势.
I'm trying to implement in my ViewController( which has a tableView) two gesture recognisers that have to work one after another. The first one is a swipe down gesture and the second a long press gesture.
这是我用@sergio 建议修改的代码
Here's my code modified with @sergio suggestions
- (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 子类:
And my UILongPressGestureRecognizer subclass:
#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 的日志
Unfortunately, I still get only the log from swipeDown but no log when it comes to longPress
推荐答案
为此,您需要创建自己的自定义手势识别器.最好的方法是将 UILongPressGestureRecognizer
子类化,并使其仅在滑动结束后接受"长按.例如,在 touchesBegan
方法
For that you need to create you own custom gesture recognizer. The best way would be for you to subclass UILongPressGestureRecognizer
and make it "accept" the long press only after the swipe has ended. E.g., in the touchesBegan
method
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
<if swipe recognizer action method has been called>
[super touchesBegan:touches withEvent:event];
}
}
这样,两个手势识别器都会尝试识别手势:滑动识别器会立即识别;而自定义识别器会等待"滑动识别器触发.
In this way, both gesture recognizers would try to recognize the gesture: the swipe recognizer would do so immediately; while the custom recognizer would "wait" for the swipe recognizer to have fired.
实现条件的一种简单方法是在您的滑动操作中设置一个全局标志(您在执行滑动操作时设置它;然后自定义识别器读取其值).这很简单,到目前为止还不是您能找到的最佳实现.
An easy way to implement the condition <if swipe recognizer action method has been called>
would be setting a global flag in your swipe action (you set it when the swipe action is executed; then the custom recognizer reads its value). This is easy, by far not the best implementation you can find.
另一种方法是依靠 requiresGestureRecognizerToFail
来链接 3 个标准手势识别器,我们称它们为 A、B 和 C,其中:
Another approach would be relying on the requiresGestureRecognizerToFail
to chain 3 standard gesture recognizers, let's call them A, B, and C, where:
- A 是一个
UISwipeGestureRecognizer
; - C 是一个
UILongPressGestureRecognizer
; - B 是任何手势识别器.
您可以这样配置它们:
C --> B --> A
其中 x -->y
表示 x
要求 y
失败.因此,您将拥有 C
(您的长按手势识别器)将要求 B
GR 失败,而 B
需要 A
(你的滑动识别器)失败;B
将在 A
识别出滑动后立即失败;一旦B
失败,C
将被允许识别长按(如果有).
whereby x --> y
denotes that x
requires y
to fail. Thus, you would have that C
(your long press gesture recognizer) will require the B
GR to fail and B
requires A
(your swipe recognizer) to fail; B
will fail as soon as A
will recognized the swipe; once B
fails, C
will be allowed to recognize the long press if any.
在阅读您的评论后,您是否介意尝试一下,看看是否有帮助:
after reading your comment, would you mind trying this and see if it helps out:
删除覆盖的
touchesBegan
并将其替换为:
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
}
然后定义:
then define:
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
if (vc.methodHasBeenCalled) {
[super touchesBegan:touches withEvent:event];
} else {
return;
}
}
如果这不起作用,那么让您的自定义手势识别器继承自通用手势识别器和
If this does not work, then make your custom gesture recognizer inherit from a generic gesture recognizer and
保留
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;
这篇关于结合向下滑动和长按的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!