Подтвердить что ты не робот

Как обнаружить двойные нажатия на ячейки в 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]], К сожалению, это ошибка.

4b9b3361

Ответ 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;
}