30

我想响应在 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]]. 不幸的是,这是一个错误。

4

5 回答 5

51

我不明白你为什么需要requireToFail。我在 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;

这消除了对单元选择的单击的干扰。这提供了更强大的设置。

于 2013-03-07T08:44:17.867 回答
13

这里有很多很好的解决方案,但不幸的是它们对我来说并不可靠(例如,我无法让双击持续触发,可能是因为我还实现了 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
}
于 2014-03-19T20:38:20.293 回答
5

我的解决方案是不实现 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 上选择了单元格,但如果这让您感到困扰,您可以在两个选择器中处理它。

于 2013-08-03T16:35:29.543 回答
3

默认手势识别器上的requireGestureRecognizerToFail:调用确实有效(也就是说,如果识别到双击,它们的状态将变为 UIGestureRecognizerStateFailed)。

但似乎 UICollectionView 的collectionView:didSelectItemAtIndexPath:委托回调没有考虑到这一点,即。当默认手势识别器失败时仍会调用它。

因此,答案/解决方法是确保委托collectionView:shouldSelectItemAtIndexPath:collectionView:shouldDeselectItemAtIndexPath:实现检查默认手势识别器(其中一个?)的状态,因此:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {

    UITapGestureRecognizer *defaultGestureRecogniser = [[self.collectionView gestureRecognizers] objectAtIndex:0];
    return defaultGestureRecogniser.state != UIGestureRecognizerStateFailed;
}
于 2012-10-10T05:44:18.823 回答
0

对于寻求快速答案的读者,这是@RegularExpression 和@Edwin Iskandar 答案的混合。

在您的控制器中collectionView添加以下行:


  private var doubleTapGesture: UITapGestureRecognizer!
  func setUpDoubleTap() {
    doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTapCollectionView))
    doubleTapGesture.numberOfTapsRequired = 2
    collectionView.addGestureRecognizer(doubleTapGesture)

    // This line delay the single touch message to the collection view.
    // Simple touch will be sent only when the double tap recogniser is sure
    // this is a simple tap.
    // You can remove it if you don't mind having both a simple tap and double
    // tap event.
    doubleTapGesture.delaysTouchesBegan = true  
  }

  @objc func didDoubleTapCollectionView() {
    let pointInCollectionView = doubleTapGesture.location(in: collectionView)
    if let selectedIndexPath = collectionView.indexPathForItem(at: pointInCollectionView) {
      let selectedCell = collectionView.cellForItem(at: selectedIndexPath)

      // Print double tapped cell's path
      print(selectedCell)
    }
  }
于 2019-05-30T15:49:51.563 回答