Le contrôle
Image View (figure suivante) permet d'afficher une image ou une animation, définie par l'affichage consécutif de plusieurs images. Les images sont chargées
via des objets
UIImage. Une fois l'image chargée, il suffit de l'associer à une vue et à une taille pour l'afficher.
Sans entrer dans les détails, sachez cependant que les images affichées dans un contrôle
Image View peuvent provenir de l'album photo du device, des ressources de l'application, d'Internet ou être créées par l'application elle-même. Examinons ces quatre cas.
L'image est dans l'album photo du device
Certains devices iOS disposent d'un appareil photo. Lorsqu'une photo est prise, elle est stockée dans l'album photo du device. Ce dernier est accessible par l'icône
Photos. Malheureusement, lorsque vous cliquez dessus dans le simulateur iOS, l'album photo est vide, comme à la figure suivante.
Si vous voulez utiliser le simulateur pour vous entraîner à manipuler les photos de l'album, il est donc nécessaire de le remplir avant toute chose. Le simulateur vous propose d'utiliser iTunes pour ajouter des photos dans l'album. Nous allons utiliser une tout autre technique.
- Trouvez un dossier qui contient des photos sur votre Mac.
- Glissez-déposez une photo sur l'album photo du simulateur. Quelques instants plus tard, la photo est affichée dans le navigateur Safari (1).
- Pointez la photo et maintenez le bouton gauche de la souris enfoncé jusqu'à ce qu'un menu apparaisse dans la partie inférieure de l'écran (2).
- Cliquez sur Save Image (3).
- Recommencez les étapes 2 à 4 pour ajouter une ou plusieurs autres photos.
Si vous avez du mal à comprendre, reprenez ces instructions en observant la figure suivante.
Maintenant, voyons comment accéder à ces photos.
Toute la magie réside dans l'utilisation d'un objet
UIImagePickerController. Ce contrôleur permet entre autres de sélectionner une image dans une liste. C'est exactement ce que nous voulons. La liste sera prise dans l'album photo.
Définissez un nouveau projet de type
Single View Application et donnez-lui le nom « imagePicker ». Cliquez sur
MainStoryboard.storyboard dans le volet de navigation, puis ajoutez un contrôle
Image View et un contrôle
Rounded Rect Button dans la zone d'édition. Redimensionnez-les pour obtenir quelque chose ressemblant à la figure suivante.
Reliez les deux contrôles au code en créant :
- l'outlet uneImage pour le contrôle UIImageView ;
- l'action album pour le bouton.
Le fichier
ViewController.h devrait maintenant ressembler à ceci :
Code : Objective-C | #import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIImageView *uneImage;
- (IBAction)album:(id)sender;
@end
|
Étant donné que l'objet
UIImagePickerController ne fait pas partie de la librairie d'objets Cocoa Touch, nous allons l'implémenter directement dans le code. Cliquez sur
ViewController.h dans le volet de navigation et insérez la ligne suivante dans les variables d'instance :
Code : Objective-C | UIImagePickerController *picker;
|
Le fichier
ViewController.h devrait maintenant ressembler à ceci :
Code : Objective-C | #import <UIKit/UIKit.h>
@interface ViewController : UIViewController
{
UIImagePickerController *picker;
}
@property (weak, nonatomic) IBOutlet UIImageView *uneImage;
- (IBAction)album:(id)sender;
@end
|
Lorsque l'utilisateur clique sur le bouton, nous voulons afficher la liste des images contenues dans l'album photo. Pour cela, nous allons agir sur la méthode événementielle
album. Cliquez sur
ViewController.m dans le volet de navigation puis complétez la méthode
album comme suit :
Code : Objective-C | - (IBAction)album:(id)sender {
picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:picker animated:YES];
}
|
Si vous trouvez ce code compliqué, ne paniquez pas ; je vais tout vous expliquer !
La ligne 2 initialise l'objet
picker en le reliant à la classe
UIImagePickerController.
La ligne 3 définit le delegate de l'objet
picker. C'est ce delegate qui recevra les notifications lorsque l'utilisateur sélectionnera une image ou fermera l'
Image Picker sans rien sélectionner.
La ligne 4 indique à l'
Image Picker à quel endroit il doit rechercher la liste d'images. Vous l'aurez compris, le mot
UIImagePickerControllerSourceTypePhotoLibrary fait référence à l'album photo.
Enfin, la ligne 5 applique la méthode
presentModalViewController à l'
Image Picker. Ainsi, les vignettes de l'album seront affichées dans une fenêtre « modale », c'est-à-dire dans une fenêtre située au-dessus de l'application et qui rend l'accès à cette dernière impossible.
Si vous remplacez UIImagePickerControllerSourceTypePhotoLibrary par UIImagePickerControllerSourceTypeCamera, le device prend une photo et la présente dans l'Image Picker.
Je ne sais pas si vous avez remarqué le point d'exclamation de couleur jaune en face de l'instruction
picker.delegate = self;. Il s'agit d'un avertissement. Si vous cliquez sur le point d'exclamation, Xcode affiche des informations complémentaires sur le problème, comme à la figure suivante.
Reprenons l'intitulé du message :
Code : Console | Passing 'ViewController *const\_strong' to parameter of incompatible type 'id<UINavigationControllerDelegate, UIImagePickerControllerDelegate>'
Assigning to 'id<UINavigationControllerDelegate.UIImagePickerControllerDelegate>' from incompatible type 'imagePickerViewController *' |
Cela signifie que la gestion des événements liés à l'objet
picker ne peut pas être prise en charge dans cette classe (
= self dans l'instruction).
En d'autres termes, cela signifie qu'il faut ajouter un delegate dans le fichier d'en-têtes pour traiter ces événements. Et même deux delegate, puisque
UIImagePickerController est lié à
UINavigationController.
Pour régler ce problème, retournez dans le fichier
ViewController.h et modifiez la déclaration de l'interface comme suit :
Code : Objective-C | @interface ViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate> {
...
}
|
Comme par magie, l'avertissement disparaît. En définissant ces deux delegate, nous avons indiqué au compilateur que les notifications reçues lors des manipulations de l'utilisateur dans l'
Image Picker seront prises en compte par… ces delegate et traités dans la classe de l'application.
Vous pouvez lancer l'application. Lorsque vous cliquez sur le bouton
Accéder à l'album photo, l'album photo apparaît dans une liste. Cliquez dessus pour afficher les vignettes qui représentent son contenu, comme à la figure suivante.
Consternation ! Lorsque vous cliquez sur une image, elle ne s'affiche pas sur le device !
Si vous réfléchissez un peu, c'est tout à fait normal… puisqu'aucune méthode n'a été écrite pour provoquer cet affichage.
Définissez donc la méthode suivante :
Code : Objective-C | - (void)imagePickerController:(UIImagePickerController *) Picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
uneImage.image = [info objectForKey:UIImagePickerControllerOriginalImage];
[picker dismissModalViewControllerAnimated:YES];
}
|
Cette méthode est exécutée lorsque l'utilisateur choisit une vignette dans l'
Image Picker. L'image choisie est alors affichée dans le contrôle
Image View (ligne 3 du code).
L'instruction suivante ferme la vue modale de l'
Image Picker.
Tout cela, c'est très intéressant, mais comment est-ce que j'aurais pu trouver cette méthode tout seul ? Je ne me vois vraiment pas l'inventer !
Dans tous vos développements d'applications iOS, la documentation Apple vous sera d'une très grande aide. Pour l'utiliser, posez-vous les questions suivantes : « Qu'est-ce que je veux faire ? » et « De quoi dépend l'action que je veux réaliser ? ».
Ici par exemple, vous voulez afficher une image dans le contrôle
ImageView lorsque l'utilisateur clique sur une vignette affichée dans l'
Image Picker. Vous voulez donc capturer un événement. Et comme vous le savez, les événements sont gérés par… les delegate ! C'est donc dans l'aide Apple sur un delegate que va se trouver la solution.
De quel delegate s'agit-il ? Eh bien, l'utilisateur va cliquer sur une vignette dans le contrôle
Image Picker. Il s'agit donc du delegate
UIImagePickerControllerDelegate.
Comme indiqué à la figure suivante, cliquez sur l'icône
Organizer (1), dans l'angle supérieur droit de la fenêtre Xcode pour afficher la fenêtre d'aide. Tapez « UIImagePickerControllerDelegate » dans la zone de texte
Rechercher (2) et appuyez sur la touche
Entrée de votre clavier. Plusieurs réponses sont affichées dans le volet gauche. Choisissez celle qui se trouve sous l'intitulé « Reference » (3).
Ça y est, vous avez fait le plus gros du travail. Il ne vous reste plus qu'à parcourir la page d'aide pour trouver la méthode recherchée (4).
Pour finir, vous devez implémenter une autre méthode, qui sera exécutée si l'utilisateur clique sur
Cancel pour annuler l'utilisation de l'
Image Picker. Dans ce cas, il suffira de fermer la vue modale et de supprimer l'objet
Picker. Voici le code à utiliser :
Code : Objective-C | - (void)imagePickerControllerDidCancel:(UIImagePickerController *) Picker
{
[picker dismissModalViewControllerAnimated:YES];
uneImage.image = nil;
}
|
La ligne 3 ferme la vue modale de l'
Image Picker. Quant à la ligne 4, elle efface l'image affichée dans le contrôle
Image View.
La méthode imagePickerControllerDidCancel a également été trouvée dans l'aide Apple sur le delegate UIImagePickerControllerDelegate.
L'application est entièrement opérationnelle. Il ne vous reste plus qu'à l'exécuter et à choisir l'image à afficher.
L'image est dans les ressources de l'application
Une application iOS peut « embarquer » un ou plusieurs fichiers (images, sons, textes, etc.). Dans ce cas, on dit que ces fichiers font partie des
ressources de l'application.
Avant toute chose, il va nous falloir ajouter des ressources à l'application. Pour ce faire, cliquez du bouton droit sur l'icône qui représente l'application dans le volet de navigation et choisissez
New group dans le menu contextuel, comme à la figure suivante.
Donnez le nom « Resources » au nouveau groupe (avec un seul « s »). Maintenant, il vous suffit de glisser-déposer une image depuis le Finder dans le dossier « Resources », de cocher la case
Copy items into destination group's folder (if needed) et de valider en cliquant sur
Finish (figure suivante). L'image est alors intégrée aux ressources de l'application.
Lorsqu'une image se trouve dans les ressources de l'application (1), elle est directement accessible dans la propriété
Image d'un contrôle
Image View (2), comme le montre la figure suivante.
Vous pouvez également insérer une image dans un contrôle
Image View en utilisant du code. Supposons que l'outlet
monImage ait été créé pour représenter un contrôle
Image View et que l'image
chien.jpg se trouve dans les ressources de l'application. Pour afficher cette image dans le contrôle
Image View, vous utiliserez l'instruction suivante :
Code : Objective-C | monImage.image = [UIImage imageNamed:@"chien.jpg"];
|
Simple, non ?
L'image est sur Internet
Supposons que vous vouliez afficher dans un contrôle
Image View l'image qui se trouve à l'adresse
http://www.siteduzero.com/uploads/fr/ftp/iphone/zozor.png.
Commencez par créer un nouveau projet de type
Single View Application et donnez-lui le nom « imageURL ».
Cliquez sur
MainStoryboard.storyboard dans le volet de navigation, insérez un contrôle
Image View dans le canevas et faites-lui occuper toute la surface disponible. Affichez le fichier d'en-têtes à côté du canevas en cliquant sur l'icône
Show the Assistant editor dans la barre d'outils. Contrôle-glissez-déposez le contrôle
Image View juste avant le
@end du fichier d'en-têtes et créez l'outlet
monImage.
Le fichier
imageURLViewController.h doit maintenant ressembler à ceci :
Code : Objective-C | #import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIImageView *monImage;
@end
|
Pour afficher l'image dès l'ouverture de l'application, vous allez agir sur la méthode
viewDidLoad. Cliquez sur
ViewController.m dans le volet de navigation et insérez le code suivant dans la méthode
viewDidLoad:
Code : Objective-C | - (void)viewDidLoad
{
[super viewDidLoad];
NSURL *uneImage = [NSURL URLWithString: @"http://www.siteduzero.com/uploads/fr/ftp/iphone/zozor.png"];
monImage.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: uneImage]];
}
|
Comme vous pouvez le voir, deux instructions ont été ajoutées à cette méthode.
La première définit l'objet
uneImage de type
NSURL et y stocke l'URL de l'image en utilisant la méthode
URLWithString.
La deuxième instruction lit l'image sur le Web et l'affecte à l'objet
monImage. Remarquez le chaînage des messages. Dans un premier temps, un objet
NSData est initialisé avec l'image lue sur le Web (
[NSData dataWithContentsOfURL: uneImage]). Dans un deuxième temps, cet objet est transformé en un objet
UIImage (
[UIImage imageWithData: …]. Enfin, dans un troisième temps, cet objet
UIImage est affecté au
UIImageView monImage (
monImage.image = …).
Vous pouvez lancer l'application, l'image est immédiatement affichée, comme à la figure suivante.
L'image est stockée dans la sandbox
Sur un device iOS, chaque application s'exécute dans une
sandbox (
Sandbox signifie « bac à sable » en français.) qui lui est propre. Dans cet espace, il est possible de sauvegarder des informations de tous types : textes, images, URL, etc. Ces informations peuvent être rapidement retrouvées par l'application lorsqu'elle en a besoin. Cette technique est très pratique. Elle est généralement utilisée pour stocker l'état de l'application. Lorsqu'elle est à nouveau exécutée, l'utilisateur la retrouve dans le même état que la dernière fois qu'il l'a utilisée.
Dans cette section, je vais vous montrer comment stocker et lire une image dans la
sandbox. À titre d'exemple, l'image sera lue sur le Web, sauvegardée dans la
sandbox de l'application, puis affichée dans un
Image View en la lisant dans la
sandbox.
Définissez un nouveau projet de type
Single View Application et donnez-lui le nom « sandbox ». Cliquez sur
MainStoryboard.storyboard dans le volet de navigation, insérez un contrôle
Image View dans la zone d'édition et faites-lui occuper toute la surface disponible. Affichez le fichier d'en-têtes à côté de la zone d'édition en cliquant sur l'icône
Show the Assistant editor dans la barre d'outils. Contrôle-glissez-déposez le contrôle
Image View juste avant le
@end du fichier d'en-têtes et créez l'outlet
monImage.
Le fichier
ViewController.h doit maintenant ressembler à ceci :
Code : Objective-C | #import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIImageView *monImage;
@end
|
Il est temps de s'attaquer au fichier
.m. Cliquez sur
ViewController.m dans le volet de navigation et complétez la méthode
viewDidLoad comme suit :
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | - (void)viewDidLoad
{
[super viewDidLoad];
//Récupération du fichier dans la sandbox et affichage dans le Image View
NSString *limage = [NSHomeDirectory()stringByAppendingPathComponent: @"Documents/image.png"];
UIImage *recup = [UIImage imageWithContentsOfFile: limage];
monImage.image = recup;
//Stockage d'une image Web dans la sandbox sous le nom "image.png"
NSURL *uneImage = [NSURL URLWithString: @"http://www.siteduzero.com/uploads/fr/ftp/iphone/zozor.png"];
UIImage *img = [UIImage imageWithData: [NSData dataWithContentsOfURL: uneImage]];
NSData* imageData = UIImagePNGRepresentation(img);
[imageData writeToFile:limage atomically:NO];
}
|
Toutes ces instructions ont de quoi donner la chair de poule ! Mais rassurez-vous, elles n'ont rien de bien sorcier et d'ici cinq petites minutes, vous les comprendrez parfaitement.
Comme vous pouvez le voir, cette méthode contient deux blocs d'instructions.
- Le premier retrouve l'image stockée dans la sandbox et l'affiche dans le contrôle Image View.
- Le deuxième récupère une image sur le Web et la stocke dans la sandbox sous le nom image.png.
Examinons les instructions de ces deux blocs.
Le chemin du dossier dans lequel sont stockés les fichiers de la
sandbox est retourné par la méthode
NSHomeDirectory(). À ce chemin, on ajoute le sous-dossier
Documents et le fichier
image.png. La concaténation se fait
via la méthode
stringByAppendingPathComponent. Le chemin complet du fichier
image.png est donc obtenu par l'expression suivante :
Code : Objective-C | [NSHomeDirectory()stringByAppendingPathComponent: @"Documents/image.png"];
|
Pour faciliter la manipulation de ce chemin, il est stocké dans un objet
NSString de nom
limage :
Code : Objective-C | NSString *limage = [NSHomeDirectory()stringByAppendingPathComponent: @"Documents/image.png"];
|
Pour récupérer l'image qui a été stockée à cet emplacement, il suffit d'utiliser la méthode
imageWithContentsOfFile. L'image est stockée dans un objet
UIImage de nom
recup :
Code : Objective-C | UIImage *recup = [UIImage imageWithContentsOfFile: limage];
|
L'étape finale consiste à affecter l'objet
recup à la propriété
image du contrôle
Image View, ce qui provoque l'affichage de l'image :
Code : Objective-C
Jusque-là, tout va bien. Attaquons-nous au stockage de l'image dans la
sandbox.
La première instruction définit l'objet
NSURL uneImage et y stocke l'adresse URL de l'image à rapatrier depuis le Web :
Code : Objective-C | NSURL *uneImage = [NSURL URLWithString: @"http://www.siteduzero.com/uploads/fr/ftp/iphone/zozor.png"];
|
La deuxième instruction rapatrie l'image Web et la stocke dans un objet
UIImage de nom
img :
Code : Objective-C | UIImage *img = [UIImage imageWithData: [NSData dataWithContentsOfURL: uneImage]];
|
Cette technique a déjà été étudiée dans la section précédente. C'est pourquoi nous ne nous y attarderons pas.
Malheureusement, il est impossible de stocker un objet
UIImage dans la
sandbox. Il faut au préalable le convertir en un objet
NSData. Pour cela, vous utiliserez la méthode :
- UIImagePNGRepresentation si l'image est au format PNG ;
- UIImageJPEGRepresentation si l'image est au format JPEG.
Ici, l'image étant au format PNG, nous utilisons la méthode suivante :
Code : Objective-C | NSData* imageData = UIImagePNGRepresentation(img);
|
Il ne reste plus qu'à enregistrer l'objet
NSData imageData dans la
sandbox avec la méthode
writeToFile :
Code : Objective-C | [imageData writeToFile:limage atomically:NO];
|
Lancez l'application.
Lors de la première exécution, l'écran reste désespérément blanc. Quelle en est la raison selon vous ?
Rappelez-vous : le premier bloc d'instructions affiche l'image stockée dans la
sandbox et le deuxième stocke l'image de Zozor dans la
sandbox. Lors de la première exécution, Zozor n'a pas encore été mémorisé dans la
sandbox. Quittez le simulateur avec la commande
Quitter Simulateur iOS dans le menu
Simulateur iOS et relancez l'application en cliquant sur
Run dans Xcode. Cette fois-ci, Zozor est bien affiché dans le contrôle
Image View.
Vous trouverez ci-après les codes de cette application.
ViewController.h
Code : Objective-C | #import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIImageView *monImage;
@end
|
ViewController.m
Code : Objective-C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 | #import "ViewController.h"
@implementation ViewController
@synthesize monImage;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
//Récupération du fichier dans la sandbox et affichage dans le Image View
NSString *limage = [NSHomeDirectory()stringByAppendingPathComponent: @"Documents/image.png"];
UIImage *recup = [UIImage imageWithContentsOfFile: limage];
monImage.image = recup;
//Stockage d'une image Web dans la sandbox sous le nom image.png
NSURL *uneImage = [NSURL URLWithString: @"http://www.siteduzero.com/uploads/fr/ftp/iphone/zozor.png"];
UIImage *img = [UIImage imageWithData: [NSData dataWithContentsOfURL: uneImage]];
NSData* imageData = UIImagePNGRepresentation(img);
[imageData writeToFile:limage atomically:NO];
}
- (void)viewDidUnload
{
[self setMonImage:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (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
|