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.

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).

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.

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 :

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.

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.

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éthodedidAccelerate
pour obtenir les valeurs instantanées de l'accélération (acceleration.x
,acceleration.y
etacceleration.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).