UIGestureRecognizer срабатывает дважды?

Я установил UITapGestureRecognizer в viewDidLoad моего контроллера представления, но каким-то образом он дважды запускает метод выбора для одного нажатия.

UITapGestureRecognizer *g = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openInMapsApp:)] autorelease];
[self.mapView addGestureRecognizer:g];

Мой метод:

-(void)openInMapsApp:(UIGestureRecognizer*)g {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@""
                                                    message:@"This will open this location in the Maps application. Continue?"
                                                   delegate:self
                                          cancelButtonTitle:@"Cancel"
                                          otherButtonTitles:@"OK",nil];
[alertView show];
[alertView release];
}

Ответы

Ответ 1

распознаватели жестов посылают действие с различным состоянием жестов. Так что это не ошибка. Обход проблемы:

 UITapGestureRecognizer *g = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openInMapsApp:)] autorelease];
[self.mapView addGestureRecognizer:g];

-(void)openInMapsApp:(UIGestureRecognizer*)g {
if(g.state != UIGestureRecognizerStateRecognized)
    return;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@""
                                                    message:@"This will open this location in the Maps application. Continue?"
                                                   delegate:self
                                          cancelButtonTitle:@"Cancel"
                                          otherButtonTitles:@"OK",nil];
[alertView show];
[alertView release];
}

Ответ 2

У меня появился двойной UIAlertView. Как показал Николас Ростов выше, это сработало для меня. Оба состояния UIGestureRecognizerStateEnded и UIGestureRecognizerStateRecognized создали новый alertView, когда в блоке использовался [alertView show]. Когда // [alertView show] закомментирован, оба они все еще появились на консоли, но произошло только одно действие.

-(void) handleTapGesture:(UIGestureRecognizer*)sender{
    if(sender.state != UIGestureRecognizerStateRecognized)
    return;

Ответ 3

Я могу подтвердить то же самое. Я отправил отчет об ошибке в Apple с примером проекта, демонстрирующим проблему.

Временное обходное решение, которое я нашел, - это немедленно отключить UITapGestureRecognizer перед показом оповещения. Затем в методе (-ях) делегирования UIAlertView, который вы реализуете, снова включите. Это требует от вас как-то отслеживать GR, но это кажется самым элегантным решением для времени.

Используя пример кода выше:

-(void)openInMapsApp:(UIGestureRecognizer*)g {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@""
                                                message:@"This will open this location in the Maps application. Continue?"
                                               delegate:self
                                      cancelButtonTitle:@"Cancel"
                                      otherButtonTitles:@"OK",nil];
    g.enabled = NO;
    self.activeGestureRecognizer = g;
    [alertView show];
    [alertView release];
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    self.activeGestureRecognizer.enabled = YES;
    self.activeGestureRecognizer = nil;
}

- (void)alertViewCancel:(UIAlertView *)alertView {
    self.activeGestureRecognizer.enabled = YES;
    self.activeGestureRecognizer = nil;
}

Ответ 4

У меня была та же проблема, и я заметил, что второе событие имеет состояние UIGestureRecognizerStateCancelled (тогда как первым был UIGestureRecognizerStateEnded), поэтому другим обходным путем является игнорирование события в этом случае.

Ответ 5

Я только что решил аналогичную проблему. Оказалось, что у меня было добавлено два распознавателя жестов с помощью одного и того же вызова. То, как я узнал, - это NSLogging распознавателя жестов при вызове селектора.

На вашем месте я бы проверял, чтобы у вас не было двух распознавателей жестов: один из раскадровки, а другой - программно, например.

NSLog(@"recognizer: %@",[gestureRecognizer description]);

Ответ 6

Я добавил таймер в представление, которое проверяет, чтобы прикосновение было по крайней мере полсекунды назад и игнорировало второе касание, если оно слишком скоро.

Это только обходной путь. Я все равно хотел бы исправить настоящую проблему.

Ответ 7

if(g.state != UIGestureRecognizerStateBegan)
//instead of if(g.state != UIGestureRecognizerStateRecognized)
return;

Это вызовет предупреждение сразу после события жестов. например: если вы используете событие longtap, предупреждение будет отображаться после выключения вашего пальца. Но состояние UIGestureRecognizerStateBegan будет вызываться автоматически, если распознавание автоматически распознается.

Ответ 8

Я сделал это и работал:

сначала инициализируйте элемент на вашем объекте обработки, который хранит последний салфетки NSTimeInterval

-(id)initWithResourcePath:(NSString*)path  {

    if ([super init]) {
        //some code


        lastSwipe = 0;
    }
    return self;

}

Затем добавьте этот код в свой метод

-(void)viewDetectedRightSwipe:(UISwipeGestureRecognizer*)recognizer {


//touch being registered    
NSTimeInterval thisTouch = [NSDate timeIntervalSinceReferenceDate];

//if the last swipe is the first swipe, then there nothing to do but the handling of a correct gesture
if(lastSwipe !=0) {
    // find out how much time has passed between gestures
    NSTimeInterval timeSinceLastTouch = thisTouch -lastSwipe ;

    NSLog(@"thisTouch = %f",thisTouch);
    NSLog(@"timeSinceLastTouch = %f",timeSinceLastTouch);
    if (timeSinceLastTouch<0.2f) {
        //return if this is an invalid touch
        return;
    } else {
        // register the timestamp if it is valid
        lastSwipe = thisTouch;
        NSLog(@"left");
    }

} 
// invalid gestures won't be registed because they won't get to this portion of code.
lastSwipe = thisTouch;
NSLog(@"left");
// rest of the handling code
}