2009-05-26 5 views
14

J'ai une petite question concernant les touches de suivi sur l'iPhone et je semble ne pas être en mesure de parvenir à une conclusion sur ce point, donc des suggestions/idées sont très appréciés:iPhone: Suivi/Identification des touches individuelles

I vouloir être en mesure de suivre et d'identifier les touches sur l'iPhone, c'est à dire. fondamentalement chaque contact a une position de départ et une position actuelle/déplacée. Les touches sont stockées dans un vecteur std :: et elles doivent être retirées du conteneur, une fois terminées. Leur position doit être mise à jour une fois qu'ils ont bougé, mais je veux quand même savoir où ils ont commencé (reconnaissance gestuelle). Je reçois les contacts de [event allTouches], le NSSet n'est pas trié et je ne suis pas en mesure d'identifier les touches qui sont déjà stockées dans le fichier std :: vector et je fais référence aux touches du fichier. NSSet (donc je sais lesquels sont terminés et doivent être enlevés, ou ont été déplacés, etc.)

Voici mon code, qui fonctionne parfaitement avec un seul doigt sur l'écran tactile, bien sûr, mais avec plus d'un , J'obtiens des résultats imprévisibles ...

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    [self handleTouches:[event allTouches]]; 
} 

- (void) handleTouches:(NSSet*)allTouches 
{ 
    for(int i = 0; i < (int)[allTouches count]; ++i) 
    { 
     UITouch* touch = [[allTouches allObjects] objectAtIndex:i]; 
     NSTimeInterval timestamp = [touch timestamp]; 

     CGPoint currentLocation = [touch locationInView:self]; 
     CGPoint previousLocation = [touch previousLocationInView:self]; 

     if([touch phase] == UITouchPhaseBegan) 
     { 
      Finger finger; 
      finger.start.x = currentLocation.x; 
      finger.start.y = currentLocation.y; 
      finger.end = finger.start; 
      finger.hasMoved = false; 
      finger.hasEnded = false; 

      touchScreen->AddFinger(finger); 
     } 
     else if([touch phase] == UITouchPhaseEnded || [touch phase] == UITouchPhaseCancelled) 
     { 
      Finger& finger = touchScreen->GetFingerHandle(i); 

      finger.hasEnded = true; 
     } 
     else if([touch phase] == UITouchPhaseMoved) 
     { 
      Finger& finger = touchScreen->GetFingerHandle(i); 

      finger.end.x = currentLocation.x; 
      finger.end.y = currentLocation.y; 
      finger.hasMoved = true; 
     } 
    } 

    touchScreen->RemoveEnded(); 
} 

Merci!

Répondre

7

Pour résoudre votre problème, utilisez votre méthode "handleTouches". La première chose que vous faites dans votre méthode handleTouches, c'est de l'allumer sur le touchPhase, mais cela vous est déjà donné. Si vous recevez le toucher dans les touchesBegan, vous savez que le toucher est dans UITouchPhaseBegan. En canalisant les touches des méthodes à quatre touches en une seule méthode, vous défaites le but d'avoir quatre méthodes de délégué.

Dans chacune de ces méthodes, Apple vous donne l'opportunité de gérer une phase différente du contact actuel. La deuxième chose est que vous n'avez pas besoin de rechercher l'événement pour le toucher en cours, il vous est donné en paramètre: touches.

Un événement est composé d'ensembles de touches. Pour la commodité, vous êtes donné les touches actuelles, même si elle peut également être trouvée dans l'événement. Donc, dans touchesBegan, vous commencez à suivre un contact. J'utilise un tableau de dictionnaires pour contenir mes données tactiles. Essayez de séparer votre code et déplacez-le dans la méthode tactile appropriée.

Pour la direction, Apple a quelques exemples de projets qui se concentrent sur les touches et vous montrer comment configurer ces méthodes.Rappelez-vous que ces méthodes seront appelées automatiquement pour chaque touche pendant chaque phase, vous n'avez pas besoin de parcourir l'événement pour savoir ce qui s'est passé.

Le pointeur sur chaque ensemble de touches reste constant, seules les données changent. En outre, je voudrais lire la section guide de programmation iPhone OS sur la gestion des événements qui va plus loin dans ce que j'ai dit ci-dessus avec plusieurs diagrammes expliquant la relation des touches aux événements au fil du temps.

Un extrait:

Dans iPhone OS, un objet UITouch représente une touche, et un objet UIEvent représente un événement. Un objet événement contient tous les objets tactiles pour la séquence multi-touch actuelle et peut fournir des objets tactiles spécifiques à une vue ou une fenêtre (voir Figure 3-2). Un objet tactile est persistant pour un doigt donné pendant une séquence, et UIKit le mute lorsqu'il suit le doigt tout au long de celui-ci. Les attributs tactiles qui changent sont la phase du contact , son emplacement dans une vue, son emplacement précédent et son horodatage. Le code de gestion d'événement évalue ces attributs pour déterminer comment répondre à l'événement.

+1

Je suis d'accord avec vous. Je divise mon code en méthodes appropriées. Cependant, mon problème est que j'ai besoin de créer un lien entre Obj-C et C++ et que mon architecture de jeu nécessite que l'entrée soit interrogée au lieu d'être traitée une fois que les événements sont déclenchés. C'est pourquoi je stocke les touches dans un vecteur STL. De toute façon, vos informations sur l'objet UITouch étant persistantes au fil du temps ont beaucoup aidé. Maintenant, j'utilise l'adresse de l'objet comme clé pour identifier un contact de manière unique. Fonctionne comme un charme. Je vous remercie. – FlorianZ

+0

"Si vous recevez le toucher dans les touchesBegan, vous savez que le toucher est dans UITouchPhaseBegan" - vraiment? Cela me semble faux - d'après les docs d'Apple, ils semblent dire le contraire: avec MultiTouch, une touche de touchesBegan pourrait être dans n'importe quelle phase. – Adam

+0

@Adam vous pourriez être mal lu. Bien que les touches qui sont contenues dans l'événement peuvent être dans une autre phase. Toutes les touches du paramètre "touch" sont garanties dans la phase spécifiée. À partir du Guide de gestion des événements: «Si, pour une raison ou une autre, vous êtes intéressé par les touches de la séquence multitouch actuelle qui n'ont pas changé depuis la dernière phase ou qui se trouvent dans une autre phase que l'ensemble passé, vous pouvez les demander à partir de l'objet UIEvent transmis. " –

0

Vous devriez être en mesure d'assembler correctement vos contacts en stockant l'emplacement précédent de toutes les touches, puis en comparant ces emplacements précédents lorsque de nouvelles touches sont détectées.

Dans votre méthode -handleTouches, vous pouvez mettre quelque chose comme ça dans votre boucle:

// ..existing code.. 
CGPoint previousLocation = [touch previousLocationInView:self]; 

// Loop through previous touches 
for (int j = 0; j < [previousTouchLocationArray count]; j++) { 
    if (previousLocation == [previousTouchLocationArray objectAtIndex:j]) { 
    // Current touch matches - retrieve from finger handle j and update position 
    } 
} 

// If touch was not found, create a new Finger and associated entry 

Évidemment, vous aurez besoin de faire du travail à intégrer dans votre code, mais je suis sûr que vous peut utiliser cette idée pour identifier correctement les contacts lorsqu'ils se déplacent sur l'écran. De plus, je viens de réaliser que CGPoint ne s'intégrerait pas correctement dans un NSArray - vous devrez envelopper ces objets NSValue (ou utiliser un type de tableau différent).

+0

Bonne idée. Pour une raison quelconque, cela n'a pas fonctionné pour moi, cependant. Il semble que les positions sont parfois éteintes. Cela peut être dû à une diminution des performances, lorsque je rends au contexte OpenGL (je travaille sur un jeu). Peut-être que les événements tactiles sont alors supprimés et que les emplacements précédents ne correspondent plus aux emplacements stockés? Merci quand même! – FlorianZ

+2

Cela m'a aussi causé un problème. Surtout quand vous déplacez beaucoup de doigts sur l'écran. Parfois, vous obtenez un emplacement qui ne correspond à aucun emplacement précédent. – Nosredna

8

Il semble que la façon «correcte» de suivre plusieurs touches soit la valeur du pointeur de l'événement UITouch.

Vous pouvez trouver plus de détails dans la section « Gestion d'un complexe séquence Multi-Touch » de cette Apple Developer Documentation

+1

Si vous ne suivez que les emplacements précédents et que vous les utilisez pour rechercher des contacts, vous ne réussirez pas. Souvent touchSnded passera dans un emplacement différent de toutes vos valeurs mises en cache. Google pour "Gestion d'une séquence complexe multi-touch" pour trouver les documents; le lien se déplace. Erica Sadun a écrit à ce sujet: http://blogs.oreilly.com/iphone/2008/10/recovering-multiple-touches.html et a également fourni du code: http://github.com/erica/iphone-3.0 -bookook-/blob/master/C08-Gestures/14-Resize% 20And% 20Rotate/main.m Je suppose que Apple souhaite qu'il pourrait refaire l'API tactile pour passer un NSArray plutôt que NSSet. –

Questions connexes