2010-11-29 7 views
12

Estoy intentando interceptar cualquier actividad (es decir, toques) que ocurra dentro de toda mi aplicación.Prueba de UIView: con evento: llamada tres veces?

En otras palabras, estoy tratando de recibir notificaciones sobre cualquier evento táctil que ocurra dentro de mi UIView principal, que contenga el resto de mis controles. Para hacerlo, pensé que el método de UIView -hitTest: withEvent: era una buena solución.

Sin embargo, cuando NSLog en este método sobrescrito antes de llamar a [super hitTest: ... withEvent: ...], veo que se llama 3 veces por cualquier toque que haga, y no puedo ver ninguna diferencia en el evento que recibo cada vez que se llama.

Aquí es cómo se implementa el método en la vista principal de mi solicitud:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    NSLog(@"hitTest:withEvent called :"); 
    NSLog(@"Event: %@", event); 
    NSLog(@"Point: %@", NSStringFromCGPoint(point)); 
    NSLog(@"Event Type: %d", event.type); 
    NSLog(@"Event SubType: %d", event.subtype); 
    NSLog(@"---"); 

    return [super hitTest:point withEvent:event]; 
} 

Y esto es lo que NSLog de un solo toque en esta vista:

2010-11-29 14:09:26.892 Application[68818:207] hitTest:withEvent called : 
2010-11-29 14:09:26.892 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37935.2 touches: {(
)} 
2010-11-29 14:09:26.892 Application[68818:207] Point: {173, 498} 
2010-11-29 14:09:26.892 Application[68818:207] Event Type: 0 
2010-11-29 14:09:26.892 Application[68818:207] Event SubType: 0 
2010-11-29 14:09:26.893 Application[68818:207] --- 
2010-11-29 14:09:26.893 Application[68818:207] hitTest:withEvent called : 
2010-11-29 14:09:26.893 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37935.2 touches: {(
)} 
2010-11-29 14:09:26.893 Application[68818:207] Point: {173, 498} 
2010-11-29 14:09:26.893 Application[68818:207] Event Type: 0 
2010-11-29 14:09:26.893 Application[68818:207] Event SubType: 0 
2010-11-29 14:09:26.893 Application[68818:207] --- 
2010-11-29 14:09:26.893 Application[68818:207] hitTest:withEvent called : 
2010-11-29 14:09:26.894 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37944.9 touches: {(
)} 
2010-11-29 14:09:26.894 Application[68818:207] Point: {173, 498} 
2010-11-29 14:09:26.894 Application[68818:207] Event Type: 0 
2010-11-29 14:09:26.894 Application[68818:207] Event SubType: 0 
2010-11-29 14:09:26.894 Application[68818:207] --- 

Cómo podría ¿Hay alguna diferencia entre esas tres notificaciones para activar la acción que quiero hacer solo una vez con un solo toque?

¡Gracias de antemano!

+0

¿Alguna vez encontró una solución limpia para esto? Estoy teniendo el mismo problema. La evaluación del tiempo parece que funcionaría, pero podría ser fácilmente susceptible a los cambios del SDK en el futuro. –

+0

¿Alguna suerte sobre por qué sucede esto? Estoy intentando resolver esto yo mismo – prostock

+0

¿Algún progreso en este tema? –

Respuesta

2

El número de respuestas a eventos que recibe depende de la jerarquía de vista.

Este método atraviesa la vista jerarquía mediante el envío de la pointInside: withEvent: mensaje a cada subvista para determinar qué subvista deben recibir un evento de toque. Si pointInside: withEvent: devuelve SÍ, , entonces la jerarquía de la subvista es atravesada; de lo contrario, su rama de se ignora la jerarquía de vista. Usted rara vez necesita llamar a este método usted mismo, pero puede anularlo a ocultar eventos táctiles de las subvistas.

Este método ignora objetos de vista que están ocultos, que ha desactivado la interacción del usuario , o que tienen un nivel alfa menos de 0,01. Este método no toma el contenido de la vista en la cuenta al determinar un golpe. Por lo tanto, una vista puede devolverse incluso si el punto especificado se encuentra en una parte transparente del contenido de esa vista.

Los puntos que están fuera de los límites del receptor nunca son reportados como golpes, aunque de hecho se encuentra dentro de un de subvistas del receptor. Esto puede ocurrir si la propiedad clipsToBounds de la vista actual está establecida en NO y la subvista afectada se extiende más allá de los límites de la vista.

A partir del UIView Class Reference.

En pocas palabras, si la vista que toca tiene tres subvistas, y esas vistas son visibles y están dentro de los límites de su supervista y región táctil, recibirá tres respuestas de prueba de golpe.

+1

Bueno, mi vista principal contiene más de tres subvistas, así que ¿no debería recibir más de 3 respuestas? Además, hacer la misma prueba con un nuevo proyecto que contiene solo 1 vista me da exactamente los mismos resultados. –

+0

¿Está usando el simulador o el dispositivo real? –

+0

Hmmm .. Solo probé en el simulador. Probé con el dispositivo real y volví a llamarlo –

10

De hecho, hay 3 llamadas a hitTest. No está claro por qué, pero podemos suponer por las marcas de tiempo en el evento que las dos primeras llamadas tienen que ver con completar el gesto anterior - esas marcas de tiempo siempre están muy cerca de cada vez que el toque anterior sucedió, y estarán a cierta distancia del tiempo actual.

Ésta es la forma en la que determino HitTest al proceso:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 
    NSTimeInterval system = [[NSProcessInfo processInfo] systemUptime]; 

    if (system - event.timestamp > 0.1) { 
    // not the event we were interested in 
    } else { 
    // use this call 
    } 
} 
+1

parece un poco hacky, pero funciona :) –

7

Si esto sigue siendo un problema para usted.

Encontré varios ejemplos y discusiones sobre este tema, pero la solución adecuada es bastante simple.

En general, se llama tres veces a hittest dentro de UIView o UIScrollView, esto se produce al atravesar la jerarquía de vistas.

Una muy simple y para mí la solución siempre adecuado es:

aplicar la hittest función en la vista que ha implementado

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 

para mí - las tres llamadas de función tienen siempre la misma posición - por lo que sólo almacena la ubicación en tu clase local.

en el archivo .h:

@interface MyScrollView : UIScrollView { 
    CGPoint touchLocation_; 
} 

@property (nonatomic, readonly) CGPoint touchLocation; 

en el archivo .m

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ 
    return [super hitTest:point withEvent:event]; 
} 

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ 
// The point check you need  
    if(point.y != self.touchLocation.y){ 
     touchLocation_ = point; 
    // The function call you need - just called once. 
    } 
    return [super pointInside:point withEvent:event]; 
} 

Esta solución funciona para mí en varios proyectos bastante bien.

Cuestiones relacionadas