2010-05-26 16 views
40

Estoy intentando obtener un UIGestureRecognizer que funcione con una UIWebview que es una subvista de UIScrollView. Esto suena extraño, pero cuando configuro el numberOfTouchesRequired en 2, el selector se dispara, pero cuando numberOfTouchesRequired se establece en uno, el selector no se dispara.¿UIGestureRecognizer funciona en un UIWebView?

Aquí está mi código:

UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(select1:)]; 
    tap1.numberOfTouchesRequired = 2; 
    tap1.numberOfTapsRequired = 1; 
    tap1.delegate = self; 
    [self.ans1WebView addGestureRecognizer:tap1]; 
    [tap1 release]; 

- (void) select1:(UILongPressGestureRecognizer *)sender { 
    //Do Stuff 
} 

He confirmado esto usando la muestra de Apple para UIGestureRecognizer e insertando una vista web en su punta. Su código de tap funciona en todas partes pero dentro del área de la vista web.

Respuesta

66

Por lo que he visto, UIWebView no funciona bien con los demás. Para reconocedores gesto, podría intentar volver SÍ a partir de:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer; 

que tenía que ser compatible con 3.0 por lo que terminaron haciendo todo el manejo con Javascript dentro del UIWebView gesto. No es una buena solución, pero funcionó para mis necesidades. Pude capturar una pulsación larga en un elemento, así como tocar, deslizar, pellizcar y rotar. Por supuesto, estaba usando solo contenido local.

Editar:

Usted puede mirar en PhoneGap para un ejemplo de envío de mensajes a la delegada del UIWebView. En pocas palabras, se utiliza document.location = "myscheme:mycommand?myarguments" continuación, analizar el comando y los argumentos de esta devolución de llamada delegado:

-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType { 
    if ([[[inRequest URL] absoluteString] hasPrefix:@"myscheme:"]) { 
    //.. parse arguments 
    return NO; 
    } 
} 

Se puede ver en el código PhoneGap que configurar una cola y un temporizador para enviar los mensajes. Dependiendo de su uso, es posible que deba hacer lo mismo. Hay otras preguntas sobre SO sobre este tema.

Aquí está la documentación Event Handling. En mi caso he añadido a los detectores de eventos document de <body onload="myloader();">

function myloader() { 
    document.addEventListener('touchcancel' , touch_cancel , false); 
    document.addEventListener('touchstart' , touch_start , false); 
    document.addEventListener('touchmove' , touch_move , false); 
    document.addEventListener('touchend' , touch_end , false); 
}; 

El manejo de eventos real depende en gran medida de sus necesidades. Cada controlador de eventos recibirá un TouchEvent con una propiedad de toques donde cada elemento es Touch. Puede registrar la hora y la ubicación de inicio en su controlador Touchstart. Si los toques se mueven demasiado o pasa la cantidad de tiempo incorrecta, no es un toque prolongado.

WebKit puede tratar de manejar un toque largo para comenzar una selección y copia. En su controlador de eventos puede usar event.preventDefault(); para detener el comportamiento predeterminado. También encontré la propiedad de css -webkit-user-select:none a mano para algunas cosas.

var touch = {}; 
function touch_start(event /*TouchEvent*/ { 
    event.preventDefault(); 
    touch = {}; 
    touch.startX = event.touches.item(0).pageX; 
    touch.startY = event.touches.item(0).pageY; 
    touch.startT = (new Date()).getTime(); 
} 

Este es solo el segundo proyecto con el que he usado javascript. Puedes encontrar mejores ejemplos en otros lugares.

Como puede ver, esta no es una respuesta rápida a su problema. Estoy muy contento con los resultados que obtuve. El html con el que estaba trabajando no tenía elementos interactivos más allá de uno o dos enlaces.

+3

Gracias, no sé nada de Javascript; ¿Sería tan amable de señalarme en la dirección correcta sobre cómo detectar un toque en un UIWebView a través de Javascript y llamar a un método Objective-C? No me importaría ser compatible con 3.0 para la orientación no iPad. Para cualquier otro que solo se preocupe por 3.2+, solucioné mi problema simplemente creando una vista transparente justo encima de UIWebView y detectando los toques en el mismo. Gracias – rscott

+0

dat trabajó – user578386

+0

Gracias, funciona bien –

1

También puede encontrar mi respuesta here útil. Es un ejemplo práctico de cómo manejar el gesto de pellizco en javascript de UIWebView.

(Si lo desea, puede comunicar los eventos al Objective-C. Consulte my answer here.)

44

UIWebView tiene sus propias vistas privadas, que también tienen identificadores de gestos adjuntos. Por lo tanto, las reglas de precedencia evitan que cualquier reconocedor de gestos agregado a UIWebView funcione correctamente.

Una opción es implementar el protocolo UIGestureRecognizerDelegate e implementar el método gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer. Regrese SÍ de este método para otros gestos de toque. De esta forma, se llamará a su controlador de acceso y la vista web seguirá recibiendo su llamada.

Ver this on the Apple dev forums.

+1

Ver la segunda respuesta en cuestión de información suplementaria: http://stackoverflow.com/questions/2627934/simultaneous-gesture-recognizers-in-iphone-sdk – ChrisP

+0

Deseo Podría votar esto más de una vez. –

+0

Esto es extremadamente útil, ¡gracias! –

4

Estaba teniendo el mismo problema. Esta solución funcionó para mí:

1) Asegúrese de añadir el protocolo a su interfaz: UIGestureRecognizerDelegate por ejemplo:

@interface ViewController : UIViewController <SlideViewProtocol, UIGestureRecognizerDelegate> 

2) Agregar esta línea de código

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 
return YES 
} 

3) Configuración gesto

UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(nextSlide)]; 
swipeGesture.numberOfTouchesRequired = 1; 
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft); 
swipeGesture.cancelsTouchesInView = YES; [swipeGesture setDelegate:self]; 
[self.view addGestureRecognizer:swipeGesture]; 
+1

esta respuesta debe editarse para devolver el código correcto en el paso # 2 (es decir, que la API requiere que se devuelva un BOOL). –

+0

Esta es la más simple de las soluciones presentadas y funciona para mí, con dos advertencias. Debes regresar SÍ. Y debe establecer swipeGesture.delegate = self; – JScarry

+0

Edité la publicación para reflejar las sugerencias. – chrisallick

2

Otra forma es poner un UIButton transparente encima de UIWebView y manejar los toques desde este botón. En algunos casos, podría ser una buena solución.

UIWebView webView = [UIWebView new]; 
//... 

UIButton *transparentButton = [UIButton buttonWithType:UIButtonTypeCustom]; 
[transparentButton addTarget:self action:@selector(buttonTapped) forControlEvents:(UIControlEventTouchUpInside)]; 
transparentButton.frame = webView.frame; 
transparentButton.layer.backgroundColor = [[UIColor clearColor] CGColor]; 
[self.view transparentButton]; 
+0

Hahah, esta es definitivamente la mejor solución :) +1 para el truco. – chrisallick

+3

Uso este método si no necesito desplazarme por UIWebView. Pero si necesita desplazarse, no funciona, ya que UIButton atrapa toda la entrada del usuario. – JScarry

13

Esta es una solución un tanto hack-ish, pero funciona. UIWebView tiene muchos reconocedores de gestos internos a los que normalmente no se puede acceder sin utilizar una API privada. Sin embargo, los obtiene gratuitamente cuando implementa gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:. En ese punto, puede indicar a todos los UITAPGestureRecognizers internos que se activen solo cuando su propio UITAPGestureRecognizer haya fallado. Solo lo hace una vez y luego elimina el delegado de su propio reconocedor de gestos. El resultado es que aún puede desplazarse y desplazarse por su vista web, pero ya no recibirá ningún gesto de toque (único).

- (void)viewDidLoad 
{  
    [super viewDidLoad]; 

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; 

    // view is your UIViewController's view that contains your UIWebView as a subview 
    [self.view addGestureRecognizer:tap]; 

    tap.delegate = self; 
} 

- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer 
{ 
    NSLog(@"tap!"); 

    // this is called after gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: so we can safely remove the delegate here 
    if (gestureRecognizer.delegate) { 
     NSLog(@"Removing delegate..."); 
     gestureRecognizer.delegate = nil; 
    } 
} 

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
{ 
    if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { 
     [otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer]; 

     NSLog(@"added failure requirement to: %@", otherGestureRecognizer); 
    } 

    return YES; 
} 

Enjoy!

3
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { 
    return YES; 
} 
Cuestiones relacionadas