简体   繁体   English

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

[英]Recognize long press and pan gesture recognizers together

I have a view to which I've added both a pan and long press UIGestureRecognizer. 我有一个观点,我已经添加了泛和长按UIGestureRecognizer。 The pan is used to move the view around. 平底锅用于移动视图。 What I'd like to do is notice also that the touch has stopped moving (while remaining active) and trigger the long press. 我想做的是注意触摸已停止移动(同时保持活动状态)并触发长按。

What I find is that the long press is never triggered after the pan has begun. 我发现在平底锅开始后从未触发长按。 I've tried setting a delegate and implementing: 我已经尝试设置委托并实现:

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

I've tried fooling with the pan gr's allowableMovement, also to no avail. 我试过愚弄pan gr的allowableMovement,也无济于事。 I'm just about to give up and use a timer in the pan gr that get's invalidated and then reset on moves, but I was hoping that the SDK would do the state machine stuff for me. 我只是放弃并在pan gr中使用一个计时器,它被取消,然后重置动作,但我希望SDK能为我做状态机的东西。

In case anyone else needs it, here's the code that works for me. 如果其他人需要它,这里的代码对我有用。 The goal is to have a view that is sensitive to both long press and pan, including a long press that isn't preceded by a pan and vice versa. 目标是使视图对长按和平移敏感,包括不按平底锅的长按,反之亦然。

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

When a pan begins or changes, start a timer. 当平底锅开始或更改时,启动计时器。 If the timer expires before the pan ends (touch releases), then we have a long press. 如果计时器在平移结束之前到期(触摸释放),那么我们需要长按。

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

We give the timer user info of the view. 我们给视图的计时器用户信息。 You might need to store other parts of the gesture state, like location, etc. Do it the same way, with the user info dictionary. 您可能需要存储手势状态的其他部分,如位置等。使用用户信息字典以相同的方式。

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

Since the timer method won't have an associated gr, factor out all of the logic that we'd normally put in the gr handler so it can be called by both the timer handler and the gr handler. 由于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");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM