• 20 heures
  • {0} Facile|{1} Moyenne|{2} Difficile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

J'ai tout compris !

Mis à jour le 21/06/2013

Accéléromètre

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Les iPhone, iPod Touch et iPad sont équipés d'un accéléromètre qui leur permet de déterminer leur orientation par rapport au sol. Dans ce chapitre, je vais vous montrer comment utiliser les données renvoyées par l'accéléromètre pour afficher l'inclinaison du device et détecter s'il a été agité.

Cela vous tente ? Allons-y de ce pas !

Mise en place de l'application

Avant de commencer

Les accélérations détectées par l'accéléromètre consistent en trois valeurs flottantes qui représentent les trois axes du device, comme indiqué à la figure suivante.

Les trois axes du device

Pour obtenir ces informations, vous utiliserez la classe UIAccelerometer. Un coup d'œil à l'aide Apple montre que les événements générés par les objets de cette classe se font via le protocole UIAccelerometerDelegate. Un autre coup d'œil à l'aide Apple sur le protocole UIAccelerometerDelegate montre que la méthode événementielle à utiliser pour recevoir les données relatives à l'accélération est didAccelerate.

Il ne reste plus qu'à implémenter un objet de la classe UIAccelerometer et à gérer les événements renvoyés par cet objet dans la méthode didAccelerate pour connaître la position du device.

Définition de l'interface de l'application

Définissez un nouveau projet de type Single View Application et donnez-lui le nom « accelerometre ».

Une fois le projet créé, cliquez sur MainStoryboard.storyboard dans le volet de navigation. Ajoutez un contrôle Label à la vue de l'application. Double-cliquez dessus et tapez « Accéléromètre » au clavier. Choisissez une police à votre convenance et un corps élevé pour que ce Label fasse office de titre (pour l'exemple, j'ai choisi une police Helvetica de corps 43).

Vous pouvez modifier la police et le corps du Label

Insérez quatre autres Label dans la partie inférieure de la vue. Déplacez-les et alignez-les pour obtenir quelque chose ressemblant à la figure suivante.

Ajoutez des Label et disposez-les de la sorte

Liaison des contrôles au code

Pour que l'application puisse afficher des informations dans les quatre derniers Label, vous devez établir un lien entre l'interface et le code.

Affichez côte à côte la zone d'édition et le fichier ViewController.h en cliquant sur l'icône Show the Assistant editor dans la barre d'outils.

Contrôle-glissez-déposez tour à tour les quatre derniers Label et définissez les outlets x, y, z et mouvement. Le fichier ViewController.h doit maintenant ressembler à ceci :

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *x;
@property (weak, nonatomic) IBOutlet UILabel *y;
@property (weak, nonatomic) IBOutlet UILabel *z;
@property (weak, nonatomic) IBOutlet UILabel *mouvement;
@end

Écriture du code

L'interface et le fichier d'en-têtes étant définis, il ne reste plus qu'à écrire un peu de code pour faire fonctionner tout ce petit monde. Cliquez sur ViewController.m dans le volet de navigation.

Dans un premier temps, vous allez ajouter un arrière-plan à l'application. Définissez un dossier Resources dans l'arborescence de l'application, procurez-vous une image de 320x480 pixels et ajoutez-la à ce dossier.

Pour que l'image d'arrière-plan s'affiche dès l'ouverture de l'application, ajoutez l'instruction suivante dans la méthode viewDidLoad (cette instruction suppose que l'image d'arrière-plan a pour nom « gyro.jpg ») :

self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"gyro.jpg"]];

Vous allez maintenant définir un objet de classe UIAccelerometer et l'initialiser. Complétez la méthode viewDidLoad comme suit :

- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"gyro.jpg"]];
UIAccelerometer *testAccel = [UIAccelerometer sharedAccelerometer];
testAccel.delegate = self;
testAccel.updateInterval = 0.1f;
[mouvement setText:@"Le device est calme"];
}

À la ligne 5, nous définissons l'objet testAccel de type UIAccelerator. Cet objet est initialisé avec la méthode sharedAccelerometer, comme indiqué dans la documentation Apple :

UIAccelerometer *testAccel = [UIAccelerometer sharedAccelerometer];

La ligne 6 indique que les événements relatifs à l'objet testAccel seront traités dans la classe courante, c'est-à-dire dans la classe de la vue :

testAccel.delegate = self;

À la ligne 7, nous utilisons la propriété updateInterval pour définir la période de la mise à jour des données fournies par l'accéléromètre. Ici, tous les 1/10 seconde :

testAccel.updateInterval = 0.1f;

Enfin, la ligne 8 affiche le message « Le device est calme » dans le Label mouvement pour indiquer que le device n'est pas agité :

[mouvement setText:@"Le device est calme"];

Si je me souviens de ce qui a été dit au début de cette section, il est nécessaire d'implémenter le protocole UIAccelerometerDelegate. Est-ce qu'il ne faudrait pas agir sur le fichier d'en-têtes pour cela ?

Tout à fait exact. D'ailleurs, le message d'avertissement affiché en face de la ligne testAccel.delegate = self; (figure suivante) le confirme :

Un message d'erreur apparaît

Cliquez sur ViewController.h dans le volet de navigation et ajoutez la référence au delegate dans l'instruction @interface :

@interface accelerometreViewController : UIViewController <UIAccelerometerDelegate>
{
...
}

En consultant la documentation Apple relative à UIAccelerometerDelegate, vous verrez que la méthode didAccelerate est appelée lorsque de nouvelles données issues de l'accéléromètre sont disponibles. Définissez cette méthode comme suit :

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
if (fabsf(acceleration.x) > 1.5 || fabsf(acceleration.y) > 1.5 || fabsf(acceleration.z) > 1.5)
{
[mouvement setText:@"J'ai détecté une secousse"];
if (temporisation == 0)
temporisation = 1;
}
x.text=[NSString stringWithFormat:@"%@ %f",@"X =",acceleration.x];
y.text=[NSString stringWithFormat:@"%@ %f",@"Y =",acceleration.y];
z.text=[NSString stringWithFormat:@"%@ %f",@"Z =",acceleration.z];
if (temporisation > 0)
temporisation++;
if (temporisation == 30)
{
[mouvement setText:@"Le device est calme"];
temporisation = 0;
}
}

N'ayez crainte, il n'y a rien de bien méchant dans cette méthode !

Si le gabarit de la méthode vous semble compliqué, sachez qu'il a été automatiquement proposé par Xcode dès la saisie du mot accelerometer, comme le montre la figure suivante.

Xcode vous propose automatiquement le gabarit de la méthode

Les accélérations selon les axes X, Y et Z sont accessibles dans les propriétés x, y et z de l'objet acceleration. L'instruction de la ligne 3 teste si l'accélération du device est supérieure à 1,5 selon un des axes :

if (fabsf(acceleration.x) > 1.5 || fabsf(acceleration.y) > 1.5 || fabsf(acceleration.z) > 1.5)

Dans ce cas, le device a été agité, et un texte est affiché en conséquence dans le Label mouvement :

[mouvement setText:@"J'ai détecté une secousse"];

Rappelez-vous : la mise à jour des quatre Labels se fait 10 fois par seconde. Il est donc nécessaire de mettre en place un artifice pour que le texte « J'ai détecté une secousse » reste affiché plus longtemps, sans quoi il sera pratiquement impossible de le voir. C'est le rôle des deux instructions qui suivent :

if (temporisation == 0)
temporisation = 1;

La variable temporisation vaut 0 par défaut. Elle indique que le device n'a pas été agité. Elle est mise à 1 pour indiquer que le device vient d'être agité.

Les lignes 10 à 12 affichent les valeurs des accélérations dans les labels x, y et z :

x.text=[NSString stringWithFormat:@"%@ %f",@"X =",acceleration.x];
y.text=[NSString stringWithFormat:@"%@ %f",@"Y =",acceleration.y];
z.text=[NSString stringWithFormat:@"%@ %f",@"Z =",acceleration.z];

Il n'y a pas grand-chose à dire au sujet de ces instructions. D'une façon très classique, la méthode stringWithFormat est utilisée pour concaténer deux éléments (ici, un texte et un flottant) et les convertir en un NSString.

Le bloc d'instructions suivant est plus intéressant. C'est lui qui se charge d'afficher le texte « J'ai détecté une secousse » pendant trois secondes.
Si la variable temporisation est supérieure à 0, on l'incrémente :

if (temporisation > 0)
temporisation++;

Si elle a pour valeur 30, ou en d'autres termes, si elle est passée une trentaine de fois par ce code (28 exactement), cela signifie qu'environ 3 secondes se sont écoulées depuis l'affichage du texte « J'ai détecté une secousse » dans le Label :

if (temporisation == 30)

Dans ce cas, le texte « Le device est calme » est affiché dans ce même Label et la variable temporisation est mise à 0, en attendant que le device soit agité une nouvelle fois :

{
[mouvement setText:@"Le device est calme"];
temporisation = 0;
}

Pour que ce code fonctionne, deux petites lignes doivent être ajoutées.

La variable temporisation doit être initialisée à 0 dans la méthode viewDidLoad :

- (void)viewDidLoad
{
...
temporisation = 0;
...
}

La variable temporisation doit être déclarée dans le fichier d'en-têtes :

@interface accelerometreViewController : UIViewController <UIAccelerometerDelegate>
{
...
int temporisation;
}

Ça y est, l'application est entièrement fonctionnelle. Vous pouvez la lancer (pas dans le simulateur, évidemment !). La figure suivante représente ce que j'ai obtenu.

Mon application est terminée et fonctionnelle

Cette application se trouve dans le dossier accelerometre.

ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UIAccelerometerDelegate>
{
int temporisation;
}
@property (weak, nonatomic) IBOutlet UILabel *x;
@property (weak, nonatomic) IBOutlet UILabel *y;
@property (weak, nonatomic) IBOutlet UILabel *z;
@property (weak, nonatomic) IBOutlet UILabel *mouvement;
@end
ViewController.m
#import "ViewController.h"
@implementation ViewController
@synthesize x;
@synthesize y;
@synthesize z;
@synthesize mouvement;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:@"gyro.jpg"]];
UIAccelerometer *testAccel = [UIAccelerometer sharedAccelerometer];
testAccel.delegate = self;
testAccel.updateInterval = 0.1f;
temporisation = 0;
[mouvement setText:@"Le device est calme"];
}
- (void)viewDidUnload
{
[self setX:nil];
[self setY:nil];
[self setZ:nil];
[self setMouvement:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
if (fabsf(acceleration.x) > 1.5 || fabsf(acceleration.y) > 1.5 || fabsf(acceleration.z) > 1.5)
{
[mouvement setText:@"J'ai détecté une secousse"];
if (temporisation == 0)
temporisation = 1;
}
x.text=[NSString stringWithFormat:@"%@ %f",@"X =",acceleration.x];
y.text=[NSString stringWithFormat:@"%@ %f",@"Y =",acceleration.y];
z.text=[NSString stringWithFormat:@"%@ %f",@"Z =",acceleration.z];
if (temporisation > 0)
temporisation++;
if (temporisation == 30)
{
[mouvement setText:@"Le device est calme"];
temporisation = 0;
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
@end

En résumé

  • Les accélérations détectées par l'accéléromètre consistent en trois valeurs flottantes qui représentent les trois axes du device. Pour obtenir ces informations, vous utiliserez la classe UIAccelerometer.

  • Définissez un objet de classe UIAccelerometer, définissez la période de mise à jour des informations le concernant avec la propriété updateInterval et utilisez la méthode didAccelerate pour obtenir les valeurs instantanées de l'accélération (acceleration.x, acceleration.y et acceleration.z).

  • Pour détecter une secousse sur le device, il suffit que l'une des composantes d'accélération renvoyées par l'objet acceleration soit supérieure à une valeur donnée (1,5 par exemple).

Exemple de certificat de réussite
Exemple de certificat de réussite