tapgesture recognizer ios objective-c uicollectionview uikit uitapgesturerecognizer

ios - recognizer - Cómo detectar dobles pulsaciones en celdas en una vista Uollollection



tapgesture recognizer swift (4)

Hay un montón de buenas soluciones aquí, pero desafortunadamente no funcionaron de manera confiable para mí (por ejemplo, no pude hacer que la doble pulsación se disparara de manera consistente posiblemente porque también se implementó didSelectItemAtIndexPath).

Lo que funcionó para mí fue agregar el reconocedor de gestos (dobles) a la vista de colección en lugar de a la celda. En su selector de acción, yo determinaría qué celda se utilizó dos veces y haría lo que fuera necesario. Esperemos que esto ayude a alguien:

- (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 }

Quiero responder a los toques dobles en las celdas de un UICollectionView, y tener una selección de celdas para cancelar la acción del doble toque.

Esto es lo que he intentado:

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];

Es decir, estoy intentando que los reconocedores de gestos predeterminados fallen si mi reconocedor de gestos de doble toque tiene éxito.

Esto no parece funcionar, ya que mi colección Vista del delegado de la vista de la collectionView:didSelectItemAtIndexPath: sigue recibiendo llamadas después de un doble toque

Nota sobre los documentos UICollectionViewController de Apple

La documentación de Apple es engañosa en este punto, ya que afirma que el reconocedor de gestos predeterminado es una instancia de una subclase UITapGestureRecognizer, por lo que puede seleccionarse fácilmente con [recogniser isKindOfClass:[UITapGestureRecognizer class]] . Desafortunadamente esto es un error.


Mi solución fue no implementar collectionView: didSelectItemAtIndexPath sino implementar dos reconocedores de gestos.

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];

De esta manera puedo manejar grifos simples y dobles. Lo único que puedo ver es que la celda está seleccionada en doubleTaps pero si esto te molesta, puedes manejarlo en tus dos selectores.


No veo por qué necesita el requireToFail. Utilizo toques dobles en un UICollectionView y no interfiere con mis toques individuales (utilizados para la selección).

Yo uso lo siguiente:

UITapGestureRecognizer *doubleTapFolderGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processDoubleTap:)]; [doubleTapFolderGesture setNumberOfTapsRequired:2]; [doubleTapFolderGesture setNumberOfTouchesRequired:1]; [self.view addGestureRecognizer:doubleTapFolderGesture];

Luego esto:

- (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; } } }

Parece que funciona bien: se reconoce el doble toque y puedo manejarlo como deseo (en este caso, estoy expandiendo el contenido de una carpeta). Pero un solo toque hará que se seleccione la venta pulsada, para la cual no he escrito ningún reconocimiento de gesto.

EDITAR IMPORTANTE:

Estoy revisando esta pregunta porque he visto que mi respuesta original puede estar equivocada en ciertas circunstancias, y hay una solución aparente que parece funcionar.

La siguiente línea necesita ser agregada:

doubleTapFolderGesture.delaysTouchesBegan = YES;

lo que elimina la interferencia con un solo toque para la selección de celdas. Esto proporciona una configuración mucho más robusta.


requireGestureRecognizerToFail: llamado en los reconocedores de gestos predeterminados realmente funciona (es decir, su estado pasa a UIGestureRecognizerStateFailed si se reconoce un doble toque).

Pero parece que la collectionView:didSelectItemAtIndexPath: devolución de llamada de delegado no tiene en cuenta esto, es decir. todavía se llama cuando falla el reconocedor de gestos predeterminado.

Por lo tanto, la respuesta / solución es asegurarse de que el delegado collectionView:shouldSelectItemAtIndexPath: y la collectionView:shouldDeselectItemAtIndexPath: implementaciones verifican el estado de (uno de) los reconocedores de gestos predeterminados, por lo tanto

- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath { UITapGestureRecognizer *defaultGestureRecogniser = [[self.collectionView gestureRecognizers] objectAtIndex:0]; return defaultGestureRecogniser.state != UIGestureRecognizerStateFailed; }