一起识别长按和平移手势识别器

Posted

技术标签:

【中文标题】一起识别长按和平移手势识别器【英文标题】:Recognize long press and pan gesture recognizers together 【发布时间】:2014-04-12 04:19:55 【问题描述】:

我已经添加了平移和长按 UIGestureRecognizer 的视图。平移用于移动视图。我想做的是还注意到触摸已停止移动(同时保持活动状态)并触发长按。

我发现在平底锅开始后长按永远不会触发。我试过设置一个委托并实现:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
    NSLog(@"simultaneous %@", gestureRecognizer.class);
    return YES;


- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
    NSLog(@"require fail %@", gestureRecognizer.class);

    return [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer self]];
    // also tried return YES;
    // also tried return [gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer self]];

我试过用 pan gr 的 allowableMovement 来愚弄,也无济于事。我正要放弃并在 pan gr 中使用一个计时器,该计时器已失效,然后在移动时重置,但我希望 SDK 会为我完成状态机的工作。

【问题讨论】:

我认为您将不得不使用计时器方法(或类似的方法)。 shouldRequireFailureOfGestureRecognizer: 方法不起作用,因为在您建议的场景中,平移手势识别器永远不应进入失败状态。移动之后,只要手指还在向下,我想pan gr还是会处于UIGestureRecognizerStateChanged的状态。 你是否在视图中添加了长按手势识别器? @mownier,谢谢。是的,我做到了。我不得不自己动手。 【参考方案1】:

如果其他人需要它,下面是适合我的代码。目标是获得对长按和平移都敏感的视图,包括前面没有平移的长按,反之亦然。

// setup
@property (strong,nonatomic) NSTimer *timer;          // triggers the long press during pan
@property (strong,nonatomic) UIView *longPressView;   // need this to track long press state

// view is the view we're interested in panning and long pressing
UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGR:)];
[view addGestureRecognizer:panGR];

// this starts a long press when no pan has occurred
UILongPressGestureRecognizer *longGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGR:)];
[view addGestureRecognizer:longGR];

当锅开始或变化时,启动计时器。如果计时器在平移结束(触摸释放)之前到期,那么我们有一个长按。

- (void)panGR:(UIPanGestureRecognizer *)gr 
    if (gr.state == UIGestureRecognizerStateBegan) 
        [self startTimer:gr.view];
     else if (gr.state == UIGestureRecognizerStateChanged) 
        [self startTimer:gr.view];

        // do whatever you want to do with pan state in this method
        // in my case, I'm translating the view here

     else if (gr.state == UIGestureRecognizerStateEnded) 
        if (self.longPressView) 
            [self longPressEnded];
         else 
            [self.timer invalidate];
        
    

我们提供视图的计时器用户信息。您可能需要存储手势状态的其他部分,例如位置等。使用用户信息字典以相同的方式进行操作。

- (void)startTimer:(UIView *)view 
    if (self.longPressView) return;
    [self.timer invalidate];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.8 target:self
                                                selector:@selector(longPressTimer:)
                                                userInfo:@ @"view": view repeats:NO];


-(void)longPressTimer:(NSTimer *)timer 

    self.longPressView = timer.userInfo[@"view"];
    [self longPressBegan];

由于 timer 方法没有关联的 gr,因此将我们通常放入 gr 处理程序中的所有逻辑分解出来,以便计时器处理程序和 gr 处理程序都可以调用它。

- (void)longPressGR:(UILongPressGestureRecognizer *)gr 

    if (gr.state == UIGestureRecognizerStateBegan) 
        self.longPressView = gr.view;
        [self longPressBegan];
     else if (gr.state == UIGestureRecognizerStateEnded) 
        [self longPressEnded];
    


- (void)longPressBegan 
    NSLog(@"long press began");


- (void)longPressEnded 

    self.longPressView = nil;
    NSLog(@"long press ended");

【讨论】:

这是否允许在长按之前检测到平移手势?因此,如果检测到长按,用户不会将手指从屏幕上移开然后尝试平移手势吗?【参考方案2】:

首先我们必须注册长按和翻页手势事件,例如,

let longPress = UILongPressGestureRecognizer()
longPress.delegate = self
longPress.addTarget(self, action: #selector(sendMessageLongPress(_:)))

let panGesture = UIPanGestureRecognizer()
panGesture.delegate = self
panGesture.addTarget(self, action: #selector(sendMessagePanGesture(_:)))

self.imgRecord.addGestureRecognizer(longPress)
self.imgRecord.addGestureRecognizer(panGesture)

然后我们必须设置通过委托方法捕获多个触摸事件。为此,我们必须扩展 UIGestureRecognizerDelegate 然后使用,

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool 
    return true

然后我们可以根据需要实现事件。 (在我的情况下,如果用户滑动,我想取消录制音频,那么我必须根据需要考虑触摸开始点和触摸结束点。)

【讨论】:

以上是关于一起识别长按和平移手势识别器的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView 中的长按和平移手势

iOS 手势识别器概述

Hololens开发笔记之Gesture手势识别(基本介绍)

平移手势识别器的三层混淆

如何禁用 UIScrollView 到平移手势识别器?

SWRevealViewController 平移手势识别器问题