UITapGestureRecognizer - одно касание и двойное касание


156

Я пытаюсь добавить 2 UITapGestureRecognizersк представлению, одно для одного касания и одно для событий двойного касания. Распознаватель с одним касанием работает как положено (сам по себе). Но я не могу заставить работать распознаватель двойного касания.

Пытались экспериментировать со свойствами , как: cancelsTouchesInView, delaysTouchesBeganи , delaysTouchesEndedно до сих пор не работает.

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

Документация, кажется, предполагает, что 3 свойства, упомянутые выше, могут быть использованы для этой цели. Но я просто не уверен, какие значения должны быть установлены и на какие распознаватели (одинарные, двойные или оба). Надеюсь, кто-то знакомый с этим может помочь.

Ниже приведен последний обновленный блок кода.

// ****** gesture recognizers ******

- (void)addSingleAndDoubleTapGestureRecognizersToView:(UIView *)view
{
    // single tap    
    UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector(handleSingleTapOnView:)];                                 
    [singleTapRecognizer setNumberOfTouchesRequired:1];
    [view addGestureRecognizer: singleTapRecognizer];

    // double tap 
    UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget: tableViewController action: @selector (handleDoubleTapOnView:)];        
    [doubleTapRecognizer setNumberOfTouchesRequired:2];         
    [singleTapRecognizer requireGestureRecognizerToFail: doubleTapRecognizer];
    [view addGestureRecognizer: doubleTapRecognizer];         
}

- (void)handleSingleTapOnView:(id)sender
{

}

- (void)handleDoubleTapOnView:(id)sender
{

}

30
Случайный комментарий: подчеркивание в именах переменных заставит большинство программистов Objective-C съеживаться. Что еще хуже, ваши имена переменных не являются описательными. Почему бы просто не использовать singleTapRecognizer и doubleTapRecognizer (или что-то подобное)? Это занимает больше секунды, чтобы набрать, но делает ваш код бесконечно более читабельным.
— UIAdam

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

В случае, если у кого-то еще есть подобная проблема. Я изо всех сил пытался заставить работать двойные касания и распознаватели одного касания в быстром режиме (одно касание работало нормально, но двойного касания не было). Я перетащил распознаватели на сцену, используя раскадровку. У меня были обработчики и оператор: singleTapRecognizer.requireGestureRecognizerToFail (doubleTabRecognizer) внутри моего viewDidLoad, но по-прежнему нет двойного нажатия. Моя недостающая часть головоломки заключалась в том, чтобы перетащить значок распознавателя двойного касания (из верхнего ряда сцены) на ту часть вида, где должно было быть распознано двойное касание.
— Паулюс

1
@UIAdam, использующий подчеркивание для префикса частного имени ивара в objc, довольно распространен, хотя нет? (из-за быстрого фона)
— Чарльтон Проватас

Ответы:


412
UITapGestureRecognizer *singleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doSingleTap)] autorelease];
singleTap.numberOfTapsRequired = 1; 
[self.view addGestureRecognizer:singleTap];

UITapGestureRecognizer *doubleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doDoubleTap)] autorelease];
doubleTap.numberOfTapsRequired = 2; 
[self.view addGestureRecognizer:doubleTap];

[singleTap requireGestureRecognizerToFail:doubleTap];

Примечание: если вы используете numberOfTouchesRequired это должно быть .numberOfTouchesRequired = 1;

Для Свифта

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didPressPartButton))
singleTapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.require(toFail: doubleTapGesture)

Спасибо за ответ, попробовал ваш код, но он все еще не работает. Там должно быть что-то, что я пропустил. У вас есть еще подсказка?
— Стэнли

Могу ли я иметь ваш файл реализации для этого?
— Анил Котари

@Stanley: ответ Anils должен работать, конечно же, вы также должны предоставить обработчики (doSingleTap, doDoubleTap)
— Rok Jarc

Одно касание обновляет UITableView, который работает как положено. Двойное касание, на данный момент, просто выводит лог-оператор с помощью NSLog. Я подозреваю, что статус первого респондента переходит из UIView в другое место после первого касания, так как я ничего не сделал явно с цепочкой ответов.
— Стэнли

6
Решение работает для меня. Селектор с одним касанием срабатывает после некоторой задержки.
— Владимир Обризан

47

Решение Swift 3:

let singleTap = UITapGestureRecognizer(target: self, action:#selector(self.singleTapAction(_:)))
singleTap.numberOfTapsRequired = 1
view.addGestureRecognizer(singleTap)

let doubleTap = UITapGestureRecognizer(target: self, action:#selector(self.doubleTapAction(_:)))
doubleTap.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTap)

singleTap.require(toFail: doubleTap)

В строке кода singleTap.require (toFail: doubleTap) мы вынуждаем однократное нажатие и ждем, чтобы событие касания не было двойным касанием.


31

Вам необходимо использовать requireGestureRecognizerToFail: метод. Что-то вроде этого:

[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];


Попытался использовать вызов метода «Fail» для обоих распознавателей только сейчас снова. Но все равно не работает. Если вы уже работали с двойным нажатием, поделитесь со мной своим опытом.
— Стэнли

1
Я попробовал этот точный код (такой же, как тот, что Анил опубликовал более подробно), и он работает для меня.
— UIAdam

Спасибо за комментарий, тогда еще должно быть что-то, что я пропустил с моей стороны ...
— Стэнли

Ваш код все еще мешает с задержками касаний и еще много чего. Сделайте так, чтобы он точно следовал коду Анила. Используйте requireGestureRecognizerToFail только один раз, как у нас.
— UIAdam

Сделаю, как вы посоветовали позже сегодня или завтра, так как у меня сейчас мало времени. Спасибо за вашу помощь ...
— Стэнли

15

// ---- во-первых, вы должны выделить двойной и один жест касания ------- //

UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleDoubleTap:)];

UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : @selector (handleSingleTap:)];

[singleTap requireGestureRecognizerToFail : doubleTap];
[doubleTap setDelaysTouchesBegan : YES];
[singleTap setDelaysTouchesBegan : YES];

// ----------------------- количество нажатий ---------------- //

[doubleTap setNumberOfTapsRequired : 2];
[singleTap setNumberOfTapsRequired : 1];

// ------- добавление двойного касания и однократного касания к виду или кнопке -------- //

[self.view addGestureRecognizer : doubleTap];
[self.view addGestureRecognizer : singleTap];

10

Не уверен, что это именно то, что вы ищете, но я сделал одно / двойное нажатие без распознавания жестов. Я использую его в UITableView, поэтому я использовал этот код в методе didSelectRowAtIndexPath

    tapCount++;
    switch (tapCount)
    {
        case 1: //single tap
            [self performSelector:@selector(singleTap:) withObject: indexPath afterDelay: 0.2];
            break;
        case 2: //double tap
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap:) object:indexPath];
            [self performSelector:@selector(doubleTap:) withObject: indexPath];
            break;
        default:
            break;
    }
    if (tapCount>2) tapCount=0;

Методы singleTap и doubleTap просто недействительны с NSIndexPath в качестве параметра:

- (void)singleTap:(NSIndexPath *)indexPath {
  //do your stuff for a single tap
}

- (void)doubleTap:(NSIndexPath *)indexPath {
  //do your stuff for a double tap
}

Надеюсь, поможет


Спасибо за ответ, @Novarg. У вас были проблемы с распознавателями DoubleTap?
— Стэнли

@ Stanley Нет, SingleTap ждет 0,2 секунды, прежде чем выстрелить. И если между тем был активирован второй тап, то метод singleTap отменяется.
— Novarg

Это выглядит очень многообещающе, спасибо за вашу помощь. У меня сегодня снова не хватает времени. Завтра обязательно попробую :)
— Стэнли

Креативный ответ;)
— Майкл

очень хорошее решение. Мне просто нужно было добавить tapCount = 0 на каждый обработчик (singleTap, doubleTap), чтобы быть уверенным, что следующие касания также распознаются.
— Сирио

3

Решение для Swift 2:

let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap))
singleTapGesture.numberOfTapsRequired = 1 // Optional for single tap
view.addGestureRecognizer(singleTapGesture)

let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)

singleTapGesture.requireGestureRecognizerToFail(doubleTapGesture)

1

Я реализовал методы UIGestureRecognizerDelegate для обнаружения как singleTap, так и doubleTap.

Просто сделай это.

 UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTapGesture:)];
    [doubleTap setDelegate:self];
    doubleTap.numberOfTapsRequired = 2;
    [self.headerView addGestureRecognizer:doubleTap];

    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleSingleTapGesture:)];
    singleTap.numberOfTapsRequired = 1;
    [singleTap setDelegate:self];
    [doubleTap setDelaysTouchesBegan:YES];
    [singleTap setDelaysTouchesBegan:YES];
    [singleTap requireGestureRecognizerToFail:doubleTap];
    [self.headerView addGestureRecognizer:singleTap];

Затем реализуйте эти методы делегата.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
    return  YES;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}

0

Некоторые виды имеют встроенные распознаватели двойных касаний ( MKMapViewнапример). Чтобы обойти это, вам нужно реализовать UIGestureRecognizerDelegateметод shouldRecognizeSimultaneouslyWithGestureRecognizerи вернуть YES:

Сначала реализуйте свои двойные и одиночные распознаватели:

// setup gesture recognizers
UITapGestureRecognizer* singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(mapViewTapped:)];
singleTapRecognizer.delegate = self;
singleTapRecognizer.numberOfTapsRequired = 1;


UITapGestureRecognizer* doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                      action:@selector(mapViewDoubleTapped:)];
doubleTapRecognizer.delegate = self;    // this allows
doubleTapRecognizer.numberOfTapsRequired = 2;
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];

А затем реализовать:

#pragma mark UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {  return YES; }

-1

В отношении комментария @ Стэнли -

Не пытайтесь использовать жесты касаний для выбора строк для работы, так UITableViewкак они уже полностью обработаны касаниями ....

Но вы должны установить «Отмена касаний в представлении» на «НЕТ» на ваших распознавателях жестов одним касанием, иначе оно никогда не получит события касания.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.