Как обнаружить двойные нажатия на ячейки в UICollectionView
Я хочу реагировать на двойные нажатия на ячейки в UICollectionView и иметь выбор ячейки отмены двойного касания.
Вот что я пробовал:
UITapGestureRecognizer *tapRecogniser = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
tapRecogniser.numberOfTapsRequired = 2;
for (UITapGestureRecognizer *recogniser in [self.collectionView gestureRecognizers]) {
[recogniser requireGestureRecognizerToFail:tapRecogniser];
}
[self.collectionView addGestureRecognizer:tapRecogniser];
То есть, я пытаюсь получить признак распознавания по умолчанию, если он завершит мой распознаватель жестов с двойным касанием.
Это не работает, поскольку делегат коллекции collectionView:didSelectItemAtIndexPath:
по-прежнему вызывает вызов после двойного нажатия
Примечание к документам Apple UICollectionViewController
Документация Apple вводит в заблуждение, утверждая, что распознаватель жестов по умолчанию является экземпляром подкласса UITapGestureRecognizer, поэтому его можно легко выбрать с помощью [recogniser isKindOfClass:[UITapGestureRecognizer class]]
, К сожалению, это ошибка.
Ответы
Ответ 1
Я не понимаю, зачем нужен requireToFail. Я использую double-taps в UICollectionView, и это не мешает моим одиночным кранам (используется для выбора).
Я использую следующее:
UITapGestureRecognizer *doubleTapFolderGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processDoubleTap:)];
[doubleTapFolderGesture setNumberOfTapsRequired:2];
[doubleTapFolderGesture setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:doubleTapFolderGesture];
Затем это:
- (void) processDoubleTap:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
CGPoint point = [sender locationInView:collectionView];
NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:point];
if (indexPath)
{
NSLog(@"Image was double tapped");
}
else
{
DoSomeOtherStuffHereThatIsntRelated;
}
}
}
Кажется, что он работает нормально - двойной признак распознается, и я могу обрабатывать его по своему желанию (в этом случае я расширяю содержимое папки). Но однократное нажатие приведет к тому, что выбранная продажа будет выбрана, и я не записал никакого распознавания жестов.
ВАЖНОЕ ИЗМЕНЕНИЕ:
Я пересматриваю этот вопрос, потому что я видел, что мой оригинальный ответ может быть неправильным в определенных обстоятельствах, и есть очевидное исправление, которое, похоже, работает.
Необходимо добавить следующую строку:
doubleTapFolderGesture.delaysTouchesBegan = YES;
что устраняет помехи с единственным нажатием для выбора ячейки. Это обеспечивает гораздо более надежную настройку.
Ответ 2
Здесь есть куча хороших решений, но, к сожалению, они не работают надежно для меня (например, я не мог получить двойное нажатие, чтобы запускать последовательно, потому что я также был реализован didSelectItemAtIndexPath).
Что сработало для меня, было добавление (двойной) распознавателя жестов к представлению коллекции вместо ячейки. В своем селекторе действий я бы определил, какая ячейка была двойная, и делать все, что мне нужно. Надеюсь, это поможет кому-то:
- (void)viewDidLoad
{
UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didDoubleTapCollectionView:)];
doubleTapGesture.numberOfTapsRequired = 2;
[self.collectionView addGestureRecognizer:doubleTapGesture];
}
- (void)didDoubleTapCollectionView:(UITapGestureRecognizer *)gesture {
CGPoint pointInCollectionView = [gesture locationInView:self.collectionView];
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:pointInCollectionView];
UICollectionViewCell *selectedCell = [self.collectionView cellForItemAtIndexPath:selectedIndexPath];
// do something
}
Ответ 3
Моим решением было не реализовать collectionView: didSelectItemAtIndexPath, а реализовать два распознавателя жестов.
self.doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processDoubleTap:)];
[_doubleTapGesture setNumberOfTapsRequired:2];
[_doubleTapGesture setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:_doubleTapGesture];
self.singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processSingleTap:)];
[_singleTapGesture setNumberOfTapsRequired:1];
[_singleTapGesture setNumberOfTouchesRequired:1];
[_singleTapGesture requireGestureRecognizerToFail:_doubleTapGesture];
[self.view addGestureRecognizer:_singleTapGesture];
Таким образом, я могу обрабатывать одиночные и двойные краны. Единственное, что я вижу, это то, что ячейка выбрана в doubleTaps, но если это беспокоит, вы можете обрабатывать ее в двух ваших селекторах.
Ответ 4
requireGestureRecognizerToFail:
, вызываемый признаками распознавания по умолчанию, действительно работает (то есть, их состояние переходит в UIGestureRecognizerStateFailed, если распознано двойное нажатие).
Но похоже, что вызов UICollectionView collectionView:didSelectItemAtIndexPath:
callate не учитывает это, т.е. он по-прежнему вызывается, когда дефолтный распознаватель жестов выходит из строя.
Таким образом, ответ/обходной способ заключается в том, чтобы убедиться, что реализации делегата collectionView:shouldSelectItemAtIndexPath:
и collectionView:shouldDeselectItemAtIndexPath:
проверяют состояние (одного из?) распознавателей жестов по умолчанию, таким образом:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
UITapGestureRecognizer *defaultGestureRecogniser = [[self.collectionView gestureRecognizers] objectAtIndex:0];
return defaultGestureRecogniser.state != UIGestureRecognizerStateFailed;
}