Estoy escribiendo un juego de cartas para iOS. Muestro las cartas del jugador en una vista de colección. El jugador puede seleccionar una o más cartas tocándolas y luego presionar un botón de reparto para repartir las cartas seleccionadas.
Quiero permitir que el usuario use varios dedos para seleccionar varias tarjetas a la vez. Por ejemplo, si el usuario quiere seleccionar 2 tarjetas, solo necesita tocar las dos tarjetas al mismo tiempo, con dos dedos, y ambas serán seleccionadas. Parece que, de forma predeterminada, UICollectionView no permite esto. Cuando toque con 2 dedos, solo se seleccionará una de las tarjetas, aunque la propiedad isMultipleTouchEnabled en UIView ya esté configurada como verdadera.
Tenga en cuenta que no estoy preguntando cómo permitir que un usuario seleccione varios elementos en una vista de colección. Puedo y ya lo hice con allowsMultipleSelection = true . Lo que pregunto es cómo permitir que el usuario seleccione 2 celdas con 2 dedos (o n celdas con n dedos).
Encontré esta pregunta , pero parece tratarse de cómo mostrar un borde alrededor de una celda cuando está seleccionada.
También busqué en la documentación de UICollectionView pero no encontré ninguna propiedad que controle esto.
Primero entendamos exactamente cuál es el problema. El collectionView tiene un montón de UIGestureRecognisers adjuntos (para desplazamiento, toque, zoom, etc.). Cada reconocedor tiene la misma máquina de estado de posible->reconocido->cambiado->finalizado/fallido. Cada reconocedor tiene un comienzo y un final claros. Una vez que el gesto de toque ha comenzado en una ubicación, no comenzará en otra ubicación. Cuando una persona 1) toca el punto A 2) toca el punto B 3) toca el punto A 4) toca el punto B, el gesto ignora por completo el punto B porque está "enfocado" en el punto A.
El segundo problema es que si toca dos puntos al mismo tiempo, el método de tapGesture.location(in: view) le dará el promedio de esas dos ubicaciones.
Sin embargo, resolvemos esto, el primer paso es deshabilitar collectionView tapGesture; no está haciendo lo que queremos:
self.collectionView.allowsMultipleSelection = true self.collectionView.allowsSelection = false;A continuación, agregaremos nuestros propios gestos de toque a cada celda individualmente. Apple NO lo recomienda explícitamente ("Siempre debe adjuntar sus reconocedores de gestos a la vista de la colección en sí, no a una celda o vista específica". 1 ), pero funcionará:
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 } } } }Puede agregar múltiples reconocedores de gestos para la cantidad de toques que desea admitir:
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) }y haga que el controlador busque las celdas que se tocaron:
@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: []) } } } }