2012-07-16 9 views
5

Estoy mostrando un documento en un 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.¿Cómo responder solo a un gesto de un solo toque mientras se dejan que los objetos respondan a doble toque?

Primero configuré el punto de acceso como un UIButton transparente con una acción, pero al tocar dos veces el punto de acceso público se activó dos veces la acción del punto de acceso. Así que me quité la acción desde el botón y adjuntado 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 el botón de acción normal. Pero luego he creado un gesto doble toque, y configurado 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 el el punto de acceso llama a 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 mediante la 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 Event Handling Guide for 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 el touch delivery properties 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 "abuelo", obtengo los mismos resultados.

+0

no está seguro acerca de esto (de ahí que sea un comentario), pero no se puede añadir un solo gesto grifo para UIWebView? –

+0

@DeanPucsek. Estuve haciendo eso por un tiempo y funcionó al mostrar documentos PDF. Pero si el contenido que se muestra en UIWebView es HTML o JPG, UIWebView captura el solo toque para sus propias acciones y UIGestureRecognizer no recibe el evento. Sería más conveniente manejar esto con una vista de punto de acceso, pero podría volver a este enfoque si pudiera hacerlo funcionar con todos los tipos de contenido de UIWebView. – arlomedia

Respuesta

15

Vale, he encontrado una solución en dos partes:

1) he tenido que añadir mis gestos a una vista padre de la 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 this answer.

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

  • un solo toque vista web: mi gesto de un solo toque en la vista web de vista padre responde; el gesto de un toque de la vista web también responde si corresponde porque se activan los gestos simultáneos

  • Vista web de doble toque: 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; 
} 
+0

Gracias por esta respuesta. Se enfoca más de cerca en mi situación y ofrece una solución, después de docenas de artículos leídos. Gran paz de trabajo. – vedrano

+0

Definitivamente +1. Gran explicación y buen código, probado y trabajando con Swift 2.1 –

-2

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.

Esperemos que se pueda transferir a tocar en su contexto.

+0

En realidad, en iOS, el UIGestureRecognizer tiene funcionalidad incorporada para esperar la duración de un doble toque antes de disparar un evento de un solo toque. Es por eso que puedo capturar correctamente los dos eventos usando dos reconocedores de gestos diferentes. Simplemente no sé cómo ignorar el gesto de doble toque para que llegue a UIWebView, o redirigirlo a allí, para mantener el comportamiento de zoom incorporado de la vista web. – arlomedia

+0

@arlomedia [Reenvío de eventos iOS] (https://www.google.com/search?btnG=1&pws=0&q=iOS+event+forwarding) –

+0

Revisé los resultados de búsqueda, pero no veo nada que me ayude situación. Veo algunas sugerencias de que no debería intentar reenviar eventos a los objetos UIKit, lo que me lleva de regreso a la parte "Quizás haya una manera más fácil" de mi pregunta. – arlomedia

Cuestiones relacionadas