recognizer example app ios uiwebview uikit uigesturerecognizer ios5

example - webview ios swift 4



¿Cómo responder solo a un gesto de un solo toque mientras dejas que los objetos respondan a doble toque? (2)

Estoy mostrando un documento en UIWebView. Quiero colocar un punto de acceso público sobre el documento para activar una acción cuando se toca, pero también quiero mantener el comportamiento predeterminado de UIWebView de autoenfocar el documento cuando se toca dos veces. No puedo entender cómo responder a los golpes individuales mientras dejo que UIWebView responda a los doble golpecitos.

Primero configuré el punto de acceso como un UIButton transparente con una acción, pero al hacer doble clic en el punto de acceso público, se llamaba dos veces a la acción del punto de acceso. Así que eliminé la acción del botón y agregué un gesto de un solo toque en su lugar:

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction:)]; singleTap.numberOfTapsRequired = 1; singleTap.delegate = self; [self.hotspot addGestureRecognizer:singleTap]; [singleTap release];

Esto funciona igual que la acción de botón normal. Pero luego creé un gesto de doble toque y lo configuré para bloquear el gesto de un solo toque con requireGestureRecognizerToFail:

UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(zoomWebView:)]; doubleTap.numberOfTapsRequired = 2; doubleTap.delegate = self; [self.hotspot addGestureRecognizer:doubleTap]; [doubleTap release]; UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction:)]; singleTap.numberOfTapsRequired = 1; [singleTap requireGestureRecognizerToFail:doubleTap]; singleTap.delegate = self; [self.hotspot addGestureRecognizer:singleTap]; [singleTap release]; - (void)zoomWebView:(UITapGestureRecognizer *)gesture { NSLog(@"double tap"); }

Con esta configuración, un solo toque en el punto de acceso llama singleTapAction y un doble toque en las llamadas de punto de acceso zoomWebView (un método personalizado). Esto es bueno porque singleTapAction ya no se llama dos veces, pero es malo porque UIWebView ya no responde al doble toque.

Intenté reenviar el evento de doble toque desde mi gesto doubleTap a UIWebView al crear una subclase de UITapGestureRecognizer, anulando los métodos touchesBegan y touchesEnded, y enviando sus argumentos a los métodos correspondientes de UIWebView. Cuando lo hice, pude ver que mi subclase recibía los eventos, pero UIWebView no respondió a los eventos reenviados. Esto es de esperar porque la Guía de manejo de eventos para iOS dice que solo podemos reenviar eventos a subclases personalizadas de UIView, no a objetos de marco UIKit.

¿Hay alguna manera de evitar que mi gesto de un solo toque responda a doble toque que no desvía los eventos de doble toque? Esto parece un requisito básico, pero no puedo ver una forma directa de hacerlo. Leí y experimenté con las propiedades de entrega táctil de UIGestureRecognizer, pero ninguna combinación de valores detuvo el gesto de un solo toque de consumir el gesto de doble toque.

Por cierto, la relación entre el punto de acceso y la UIWebView en mi jerarquía de vistas es la de "primos", son subvistas de dos vistas de hermanos. Si agrego los reconocedores de gestos a la vista de zona activa, la vista web o su vista de "abuelo", obtengo los mismos resultados.


Siempre ha habido un problema con los clics del mouse desde que comenzó el manejo de eventos.

Es imposible, en el caso de un solo clic, que cualquier software determine que va a suceder un doble clic.

Por lo tanto, si desea manejar un solo clic y hacer doble clic, tendrá que hacer su propio manejo con doble clic.

Mida las instancias de un solo clic y genere un evento de doble clic propio.

Con suerte, eso se puede transferir a tocar en su contexto.


De acuerdo, encontré una solución en dos partes:

1) Tuve que agregar mis gestos a una vista principal de UIWebView. Los eventos no coincidentes no viajan a través de la superposición de objetos en una vista de capa a capa, como estaba imaginando. En cambio, viajan a través de la jerarquía de puntos de vista de niño a padre. Así que, mientras añadía mi gesto de doble toque a una vista de hermano o "primo" de UIWebView, nunca iba a continuar en la vista web. Esto significa que no puedo usar botones o vistas en Interface Builder para determinar múltiples áreas de puntos de acceso. En cambio, tengo que redirigir todos los eventos de un solo golpe a un método y luego mirar las posiciones táctiles para determinar qué acción disparar.

2) Tuve que agregar el método gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer: a mi controlador de vista (el delegado de mis gestos) y devolver SÍ. Esto permite que mi gesto de toque único responda incluso cuando estoy visualizando contenido HTML, de texto o de imagen en UIWebView, que implementa su propio gesto para estos tipos de contenido. Aprendí esta parte de esta respuesta .

Con estos cambios, entiendo que la jerarquía de eventos sea:

  • Vista web de un solo toque: mi gesto de un solo toque en la vista principal de la vista web responde; el gesto de toque único de la vista web también responde si corresponde porque se habilitan los gestos simultáneos

  • Hacer doble toque en la vista web: mi gesto de doble toque en la vista principal de la vista web responde (pero no hace nada); mi gesto de un toque solo no responde porque está configurado para responder solo si falla el doble toque; el evento de doble toque de la vista web también responde porque es parte de la jerarquía de vistas (parece que la funcionalidad de doble toque de la vista web no usa un gesto porque de lo contrario tendría prioridad sobre mi propio gesto en mi configuración original) )

Con esa explicación fuera del camino, aquí hay un código de trabajo:

- (void)viewDidLoad { UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapWebView:)]; doubleTap.numberOfTapsRequired = 2; doubleTap.delegate = self; [self.webViewParent addGestureRecognizer:doubleTap]; [doubleTap release]; UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapWebView:)]; singleTap.numberOfTapsRequired = 1; [singleTap requireGestureRecognizerToFail:doubleTap]; singleTap.delegate = self; [self.webViewParent addGestureRecognizer:singleTap]; [singleTap release]; } - (void)doubleTapWebView:(UITapGestureRecognizer *)gesture { NSLog(@"double-tap"); // nothing to do here } - (void)singleTapWebView:(UITapGestureRecognizer *)gesture { NSLog(@"single-tap"); CGPoint touchLocation = [gesture locationInView:self.webViewParent]; float x = touchLocation.x; float y = touchLocation.y; CGRect frame = self.webViewParent.frame; if (y < frame.size.height * .33) { NSLog(@"top"); } else if (y > frame.size.height * .67) { NSLog(@"bottom"); } else if (x < frame.size.width * .33) { NSLog(@"left"); } else if (x > frame.size.width * .67) { NSLog(@"right"); } else { NSLog(@"center"); } } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; }