2010-11-29 25 views
12

J'essaie d'intercepter toute activité (c'est-à-dire touche) qui se produit dans toute mon application. En d'autres termes, j'essaie d'être averti de tout événement tactile qui se produit dans mon UIView principal, contenant le reste de mes contrôles. Pour ce faire, je pensais que la méthode UIView -hitTest: withEvent: était une bonne solution. Cependant, quand je NSLog dans cette méthode redéfinie avant d'appeler [super hitTest: ... withEvent: ...], je vois qu'il est appelé 3 fois pour n'importe quel contact que je fais, et je ne vois aucune différence dans l'événement que je reçois chaque fois qu'il est appelé.-hitTest de UIView: withEvent: appelé trois fois?

Voici comment est mis en œuvre la méthode dans la vue principale de ma demande:

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

Et voici ce que je NSLog pour une touche unique à ce point de vue:

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

Comment pourrais-je faire une différence entre ces trois notifications afin de déclencher l'action que je veux faire qu'une seule fois pour un seul contact?

Merci d'avance!

+0

Toujours trouver une solution propre à cela? J'ai le même problème. L'évaluation du temps semble fonctionner, mais pourrait être facilement sensible aux modifications du SDK dans le futur. –

+0

une chance sur pourquoi cela arrive? J'essaie de comprendre moi-même – prostock

+0

Des progrès sur ce problème? –

Répondre

2

Le nombre de réponses d'événements que vous recevez dépend de la hiérarchie de vues.

Cette méthode parcourt la vue hiérarchie en envoyant le pointInside: withEvent: message à chaque sous-vue de déterminer qui devrait recevoir sous-vue d'un événement tactile. Si pointInside: withEvent: renvoie YES, , la hiérarchie de la sous-vue est traversée; sinon, sa branche la hiérarchie de vue est ignorée. Vous avez rarement besoin d'appeler cette méthode vous-même, mais vous pouvez la remplacer par masquer les événements tactiles des sous-vues.

Cette méthode ne tient pas compte des objets d'affichage qui sont masqués, qui ont une interaction utilisateur désactivé , ou qui ont un niveau alpha inférieur à 0,01. Cette méthode n'inclut pas le contenu de la vue dans le compte lors de la détermination d'un hit. Ainsi, une vue peut toujours être renvoyée même si le point spécifié se trouve dans une partie transparente du contenu de cette vue.

points qui se trouvent en dehors limites ne sont jamais signalés comme coups, du récepteur, même si elles se trouvent en fait dans un des sous-vues du récepteur. Cela peut se produire si la propriété clipsToBounds de la vue actuelle est définie sur NO et la sous-vue affectée étend au-delà des limites de la vue.

Depuis le UIView Class Reference. En un mot, si la vue que vous touchez a trois sous-vues, et que ces vues sont visibles et dans les limites de leur superposition et de leur région tactile, vous recevrez trois réponses de test.

+1

Eh bien, ma vue principale contient plus de trois sous-vues, alors ne devrais-je pas recevoir plus de 3 réponses? De même, faire le même test avec un nouveau projet contenant seulement 1 vue me donne exactement les mêmes résultats. –

+0

Utilisez-vous le simulateur ou le périphérique actuel? –

+0

Hmmm .. J'ai seulement testé en simulateur. Je fais un essai sur le vrai périphérique et je reviens à vous –

10

Il y a en effet 3 appels à hitTest. On ne sait pas pourquoi, mais on peut supposer par les horodateurs sur l'événement que les deux premiers appels sont à faire avec le geste précédent - ces horodatages sont toujours très proches de chaque fois que le toucher précédent est arrivé, et seront à une certaine distance du heure actuelle.

Voici comment je déterminer qui HitTest à traiter:

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

semble un peu hacky, mais fonctionne :) –

7

Si cela est encore un problème pour vous.

J'ai trouvé plusieurs exemples et discussions sur ce sujet mais la solution appropriée est assez simple.

En général hittest est appelé trois fois dans un UIView ou un UIScrollView - ceci résulte de la traversée de la vue hiérarchique.

Un très simple et pour moi toujours la solution appropriée est:

mettre en œuvre la fonction hittest dans la vue vous mis en

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

pour moi - tous les trois appels de fonction ont toujours la même position - si juste stocker l'emplacement dans votre classe locale.

dans le fichier .h:

@interface MyScrollView : UIScrollView { 
    CGPoint touchLocation_; 
} 

@property (nonatomic, readonly) CGPoint touchLocation; 

dans le fichier .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]; 
} 

Cette solution fonctionne pour moi dans plusieurs projets très bien.