簡體   English   中英

如何檢測UICollectionView中單元格的雙擊

[英]How to detect double-taps on cells in a 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]]輕松選擇它。 不幸的是,這是一個錯誤。

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

這消除了單個抽頭對單元選擇的干擾。 這提供了更強大的設置。

這里有很多好的解決方案,但遺憾的是它們對我來說並不可靠(例如我無法通過雙擊觸發,因為我也實現了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
}

我的解決方案是不實現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上選中的,但如果這很麻煩,你可以在兩個選擇器中處理它。

requireGestureRecognizerToFail:在默認手勢識別器上調用確實有效(即,如果識別出雙擊,則其狀態將轉到UIGestureRecognizerStateFailed)。

但似乎UICollectionView的collectionView:didSelectItemAtIndexPath:委托回調沒有考慮到這一點,即。 當默認手勢識別器失敗時,它仍會被調用。

所以答案/解決方法是確保委托的collectionView:shouldSelectItemAtIndexPath:collectionView:shouldDeselectItemAtIndexPath: implements檢查默認手勢識別器的狀態(?之一),因此:

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

    UITapGestureRecognizer *defaultGestureRecogniser = [[self.collectionView gestureRecognizers] objectAtIndex:0];
    return defaultGestureRecogniser.state != UIGestureRecognizerStateFailed;
}

對於尋求快速回答的讀者來說,這是@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)
    }
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM