结合向下滑动和长按
Posted
技术标签:
【中文标题】结合向下滑动和长按【英文标题】:Combining swipe down and long press 【发布时间】:2012-12-05 15:31:37 【问题描述】:我试图在我的 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 时没有日志
【问题讨论】:
【参考方案1】:为此,您需要创建自己的自定义手势识别器。最好的方法是让您继承 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
(您的滑动识别器)失败;只要A
识别到滑动,B
就会失败;一旦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;
【讨论】:
我会试试这个,非常感谢! 还可以检查我的编辑以获取替代方法,如果您愿意,可以更做作但没有子类化。@interface CustomLongPress()
正确吗?你离开了基类......你得到touches began
跟踪吗?
是的,来自 touchesBegan 的日志正在显示,@interface CustomLongPress
是正确的
好的,那么,当您进入 touchesBegan 时,vc.methodHasBeenCalled
是什么?您会将其值添加到 NSLog 跟踪吗?【参考方案2】:
如果我没记错的话,一旦系统检测到特定类型的手势(点击、滑动、平移、长按等),它就不能再为该触摸动作发送不同类型的手势。
这并不妨碍您实现您想要的结果。也许结合重载以下UIResponder
方法:
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:
并且使用手势识别器(不确定输入是否会被一个人使用而另一个人会忽略),您可以确定它是“长滑动”
【讨论】:
以上是关于结合向下滑动和长按的主要内容,如果未能解决你的问题,请参考以下文章