samedi 19 novembre 2011

Tutorial iOS : Détection multi touch - 2 doigts

Voici un petit tutorial pour vous apprendre à détecter l'événements "multitouch", permettant notamment de pratiquer le zoom avec 2 doigts !

Tout d'abord une citation de Steve Jobs : "Dieu nous a donné 10 stylets, on a besoin de rien d'autre !" (disait-t-il à ceux qui pensaient qu'il fallait une tablette ou un smartphone équipé d'un stylet).

Vous verrez ci-dessous :
1. Comment dans une UIView détecter les événements "touch" (la détection de vos doigts).
2. Les bases du dessin dans une UIView.
3. La fonction "[self setNeedsDisplay]" qui provoque le redessin d'une vue.
4. La mise en oeuvre des événements : touchesBegan, touchesMoved, touchesEnded et touchesCancelled.
5. Les classes UIEvent et UITouch.

On utilisera également les classes :
- NSString : classe de base Objective-C pour gérer les chaînes de caractères, avec notamment son constructeur spécifique initWithFormat, très pratique pour formater une chaîne (type sprintf du langage C).
- NSSet : classe utilitaire qui retourne un jeu d'objets, à utiliser avec un NSEnumerator pour itérer dans une liste. Pour gérer plusieurs touches (touch) simultanément, on récupère la liste des endroits pressés à l'écran (vos doigts).

Pré-requis :
1. Vous aurez besoin d'un MAC équipé de l'IDE XCode (3 ou 4).
2. D'un minimum de connaissances sur le langage Objective-C (Il existe un très bon bouquin en ligne de Pierre Chatelier : ici.
3. Un véritable périphérique c'est bien mieux, avec le Simulateur dans XCode vous pourrez au moins tester un minimum.
4. Savoir rajouter un classe Objective-C héritant de UIView et attachée au controleur.

Voici la petite application en question:

Notre application à l'exécution
- Les 2 premiers champs affichés : 'width' et 'height' représentent la taille de la vue (ici la partie jaune).

- Le 'tap count' représentent la nombre d'événements 'tap' pratiqués avec les doigts. Dans beaucoup d'applications iOS on intercepte très souvent le "tap simple", souvent le "double tap".

- p1 représentent le point où se trouve le premier doigt, p2 le second doigt.



1. création du projet avec XCode (ici XCode 4)

On choisit "iOS->Application->Single View Application"



Ici on choisit un projet "IPhone"































2. Une fois le projet crée, on ajoute une classe Objective-C héritant de UIView et on attache le contrôleur à cette vue.

File -> New -> New File
















Choisir UIView comme classe mère



















3. Implémentation de la vue : fichier header


@interface MaVue : UIView {
    @private
    int     _tap_count;
    CGPoint _point1, _point2;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

@end


Les 4 méthodes ci-dessus permettent d'intercepter les touches de doigts sur l'écran.

En gros : l'événement touchesBegan se produit quand vous posez le doigt. Ensuite quand vous déplacez le doigt (ou les doigts) touchesMoved se déclenche.
touchesEnded se produit quand vous relevez le doigt.
touchesCancelled se produit par exemple quand une autre application prend le focus !

Le membre _tap_count permet de mémoriser le nombre d'événements 'tap' enregistré.

Les membres _point1 et _point2 mémorisent les localisations des doigts posés.


4. Implémentation de la vue : fichier avec le code

Ci-dessous l'implémentation des 4 événements 'touch' :


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"touchesBegan !");
    self.multipleTouchEnabled = TRUE;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"touchesMoved !");
    NSEnumerator * en = [touches objectEnumerator];
    
    UITouch * touch1 = [en nextObject];
    _point1 = [touch1 locationInView:self];
    
    UITouch * touch2 = [en nextObject];
    if( nil != touch2 ) {
        NSLog(@"touch2");
        _point2 = [touch2 locationInView:self];
    }
    
    [self setNeedsDisplay]; // invalidate the view
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"touchesEnded !");
    for (UITouch *touch in touches) 
        _tap_count = touch.tapCount;
    
    [self setNeedsDisplay]; // invalidate the view
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"touchesCancelled !");
}

- Dans la fonction touchesBegan on passe la vue en multitouch.

- Dans la fonction touchesMoved, on intercepte le déplacement des 2 doigts et on met à jour les points.

- La fonction touchesEnd met à jour le nombre de tap !



Ci-dessous la fonction de dessin de la vue :


- (void)drawRect:(CGRect) rect {
    NSLog(@"drawRect");
    UIFont   *font    = [UIFont systemFontOfSize:18.0];
    [[UIColor blueColor] set];
    
    // Affichage de la taille de la vue !
    CGPoint location = CGPointMake( 10, 20 );
    CGRect taille = [self bounds];
    NSString * tailles = [[NSString alloc] initWithFormat:@"view size width = %f", taille.size.width];
    [tailles drawAtPoint:location withFont:font];
//    [tailles release]; // dépend du système iOS utilisé
    
    location = CGPointMake( 10, 50 );
    NSString * tailles2 = [[NSString alloc] initWithFormat:@"view size height = %f", taille.size.height];
    [tailles2 drawAtPoint:location withFont:font];
//    [tailles2 release];
    
    // Affichage du nombre de tap !
    NSString * tap_count = [[NSString alloc] initWithFormat:@"tap count = %d", _tap_count];
    location = CGPointMake( 10, 80 );
    [tap_count drawAtPoint:location withFont:font];
//    [tap_count release];
    
    // Affichage du premier point !
    NSString * point1 = [[NSString alloc] initWithFormat:@"p1.x = %f, p1.y = %f", _point1.x, _point1.y];
    location = CGPointMake(10, 110);
    [point1 drawAtPoint:location withFont:font];
//    [point1 release];
    
    // Affichage du second point !
    NSString * point2 = [[NSString alloc] initWithFormat:@"p2.x = %f, p2.y = %f", _point2.x, _point2.y];
    location = CGPointMake(10, 140);
    [point2 drawAtPoint:location withFont:font];
//    [point2 release];
}


Ci-dessus le code de dessin de la vue. Cette méthode est provoquée notamment quand on appelle la fonction de re dessin de la vue : setNeedsDisplay.
On affiche les résultats à l'écran.

A vous de jouer maintenant !

Aucun commentaire:

Enregistrer un commentaire