如何检测UICollectionView中单元格的双击

时间:2012-10-09 04:05:32

标签: ios objective-c uicollectionview uikit uitapgesturerecognizer

我想对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's documentation在这一点上具有误导性,声称默认手势识别器是UITapGestureRecognizer子类的实例,因此可以使用[recogniser isKindOfClass:[UITapGestureRecognizer class]]轻松选择它。不幸的是,这是一个错误。

5 个答案:

答案 0 :(得分:44)

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

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

答案 1 :(得分:11)

这里有很多好的解决方案,但不幸的是它们对我来说不能可靠地工作(例如,我无法通过双击来一直触发,因为我也实现了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
}

答案 2 :(得分: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上选中的,但如果这很麻烦,你可以在两个选择器中处理它。

答案 3 :(得分: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;
}

答案 4 :(得分: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)
    }
  }