识别长按和平移手势识别器的组合

6

我有一个视图,其中添加了pan和long press手势识别器,pan用于移动视图。 我想做的是,当触摸停止移动(仍处于活动状态)时,也要触发长按手势。

我发现,一旦开始pan操作后就不会触发long press手势。 我尝试设置委托并实现:

- (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: 方法不会起作用,因为在你提出的场景中,平移手势识别器永远不应该进入失败状态。移动后,只要你的手指还按着屏幕,我认为平移手势识别器仍然处于 UIGestureRecognizerStateChanged 状态。 - rdelmar
你在视图中添加了长按手势识别器吗? - mownier
@mownier,谢谢。是的,我做了。我不得不自己编写。 - danh
2个回答

7

如果还有其他人需要,这是适用于我的代码。目标是拥有既敏感于长按又敏感于滑动的视图,包括不带滑动的长按事件以及没有长按的滑动事件。

// 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];
}

由于计时器方法不会有关联的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");
}

如果先前检测到长按,那么这是否允许检测到平移手势?因此,如果检测到长按,则用户不会将手指从屏幕上移开,然后尝试进行平移手势。 - George McDonnell

0
首先,我们需要注册长按和页面手势事件,如下所示:
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
}

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接