如何使用多点触控一次选择多个集合视图单元?

时间:2019-01-26 14:29:15

标签: ios swift uicollectionview multi-touch

我正在编写iOS纸牌游戏。我在收藏夹视图中显示玩家的纸牌。玩家可以通过点击选择一张或多张纸牌,然后按交易按钮来发行选定的纸牌。

我想允许用户使用多个手指一次选择多个卡。例如,如果用户要选择2张卡,他只需要用两个手指同时点击两张卡,就可以同时选择它们。似乎默认情况下,UICollectionView不允许这样做。当我用两根手指轻按时,即使isMultipleTouchEnabled中的UIView属性已设置为true,也只会选择其中一张。

请注意,我并不是在问如何允许用户在集合视图中选择多个项目。我可以并且已经使用allowsMultipleSelection = true来做到这一点。我要问的是如何允许用户选择2个手指的2个单元格(或n个手指的n个单元格)。

我找到了这个question,但这似乎与如何在选定单元格周围显示边框有关。

我还研究了UICollectionView的文档,但没有找到可控制它的属性。

2 个答案:

答案 0 :(得分:7)

首先,让我们确切地了解问题所在。 collectionView带有一堆UIGestureRecognisers(用于平移,触摸,缩放等)。每个识别器具有相同的状态机,可能->已识别->已更改->结束/失败。每个识别器都有清晰的开始和结束。一旦在一个位置开始点击手势,就不会在另一位置开始。当某人1)触摸向下点A 2)触摸向下点B 3)触摸向上点A 4)触摸向上点B时,手势完全忽略了点B,因为该手势“聚焦”在了点A上。

第二个问题是,如果您恰好同时触摸两个点,则tapGesture.location(in: view)的方法将为您提供这两个位置的平均值。

但是,我们要解决的第一步是禁用collectionView tapGesture-它没有执行我们想要的操作:

  self.collectionView.allowsMultipleSelection = true
  self.collectionView.allowsSelection = false;

接下来,我们将向每个单元格分别添加自己的点击手势。苹果显然不建议这样做(“您应该始终将手势识别器附加到集合视图本身上,而不是附加到特定的单元格或视图上。” 1),但是它将起作用:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
 ...
  cell.addGestureRecognizer(UITapGestureRecognizer.init(target: self, action: #selector(didTap(tapper:))))
  ...
  return cell;
}

@objc func didTap(tapper:UIGestureRecognizer) {
  if let cell = tapper.view as? UICollectionViewCell{
    if let index = collectionView.indexPath(for: cell) {
      if collectionView.indexPathsForSelectedItems?.contains(index) ?? false {
        collectionView.deselectItem(at: index, animated: true)
        cell.isSelected = false
      }else{
        collectionView.selectItem(at: index, animated: true, scrollPosition: [])
        cell.isSelected = true
      }
    }
  }
}

答案 1 :(得分:3)

您可以为要支持的触摸次数添加多个手势识别器:

collectionView.allowsMultipleSelection = true
// allowing up to 5 finger touches, increase if you want for more :)
for i in 2...5 {
    let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
    gestureRecognizer.numberOfTouchesRequired = i
    gestureRecognizer.delegate = self
    collectionView.addGestureRecognizer(gestureRecognizer)
}

,并让控制器查找被触摸的单元格:

@objc private func handleTap(_ gestureRecognizer: UIGestureRecognizer) {
    // perform the action only after the touch ended
    guard gestureRecognizer.state == .ended else { return }

    for i in 0..<gestureRecognizer.numberOfTouches {
        let location = gestureRecognizer.location(ofTouch: i, in: collectionView)
        // if we have a cell at that point, toggle the selection
        if let indexPath = collectionView.indexPathForItem(at: location) {
            if collectionView.indexPathsForSelectedItems?.contains(indexPath) == true {
                collectionView.deselectItem(at: indexPath, animated: true)
            } else {
                collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])
            }
        }
    }
}