Vous voilà familier avec quelques éléments du UIKit, et roi du delegate ! Il existe des manières élégantes de présenter des listes de données à l’utilisateur, encore faut-il savoir les mettre en place.
Maintenant que le delegate n’a plus de secrets pour vous, nous allons voir comment construire par le code une table view (liste de données) et des picker view (l’élément rotatif lorsque vous choisissez l’heure de votre réveil par exemple).
Commençons par créer une liste (UITableView). Il n’y a rien de plus simple !
Utilisation d’une TableView
Créez un projet Window-based Application que vous nommerez TableView et ajoutez un fichier, de type UIViewController > subclass of UITableViewController comme à la Figure 1, que vous nommerez DataListViewController.
Figure 1 : Ajouter un UITableViewController
Dans votre application delegate, ajoutez à la window la vue du DataListViewController. Petite piqûre de rappel au besoin :
Le .h
#import <UIKit/UIKit.h>
#import "DataListViewController.h"
@interface
TableViewAppDelegate :
NSObject
<UIApplicationDelegate> {
DataListViewController *dataListViewController;
}
@property
(
nonatomic
, retain)
IBOutlet
UIWindow *window;
@end
Le .m
- (
BOOL
)application:(UIApplication *)application didFinishLaunchingWithOptions:(
NSDictionary
*)launchOptions
{
dataListViewController = [[DataListViewController alloc] initWithStyle:UITableViewStylePlain];
// 1
[
self
.window addSubview:dataListViewController.view];
[
self
.window makeKeyAndVisible];
return
YES
;
}
- (
void
)dealloc
{
[dataListViewController release];
[_window release];
[
super
dealloc];
}
Ligne 1, nous pouvons remarquer que l’on peut choisir le style de la liste de données. Il en existe 2 : plain qui affiche les données comme dans le carnet d’adresses, ou grouped qui affiche les données par section, comme dans les préférences de votre iPhone/iPod Touch.
Il faut maintenant afficher des données. Dans le .h de DataListViewController, déclarer un NSArray nommé dataToShow. Dans le viewDidLoad (.m), initialisez-le comme suit :
- (
void
)viewDidLoad
{
[
super
viewDidLoad];
dataToShow = [[
NSArray
alloc] initWithObjects:@
"Element 1"
, @
"Element 2"
, @
"Element 3"
, @
"Element 4"
, @
"Element 5"
,
nil
];
}
N’oubliez pas
- (
void
)dealloc
{
[dataToShow release];
[
super
dealloc];
}
Ensuite, modifiez ces quelques lignes de code :
- (
NSInteger
)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return
1;
// 1
}
- (
NSInteger
)tableView:(UITableView *)tableView numberOfRowsInSection:(
NSInteger
)section
{
// Return the number of rows in the section.
return
[dataToShow count];
// 2
}
Ligne 1, nous spécifions le nombre de sections, comme dans la liste de votre musique dans l’application iPod (rangée par ordre alphabétique, chaque lettre correspondant à une section). Ici, nous ne nous en servons pas, il n’y a donc qu’une section. À la ligne 2, c’est le nombre de lignes que vous définissez. Ici, nous retournons le nombre d’objets de notre tableau.
Enfin, il faut afficher ces données. Pour cela, modifiez la méthode suivante :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(
NSIndexPath
*)indexPath
{
static
NSString
*CellIdentifier = @
"Cell"
;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// 1
if
(cell ==
nil
) {
// 2
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [dataToShow objectAtIndex:indexPath.row];
// 3
return
cell;
}
Cette méthode porte bien son nom. Elle demande à retourner la cellule à afficher pour chaque ligne.
Pour que le défilement de votre table view soit le plus fluide possible, il faut faire très attention à la gestion mémoire de votre cellule. Par défaut, Apple introduit un mécanisme que vous retrouvez ligne 1 où la cellule est mise en cache en fonction de CellIdentifier.
Si cette cellule n’est pas allouée, on rentre dans la condition if ligne 2 pour l’allouer. On peut choisir le style de la cellule, n’hésitez pas à parcourir la documentation pour les voir tous. Nous apprendrons à en créer une personnalisée à la section “Créer une cellule personnalisée” quelques pages plus loin. Enfin, nous allons afficher le bon élément pour la ligne demandée.
NSIndexPath comprend deux propriétés : section et row (ligne). La cellule de type UITableViewCell- StyleDefault comprend entre autres un label textLabel. Nous nous en servons pour afficher ligne 3 l’élément correspondant.
Compilez et lancez.Vous devriez obtenir quelque chose de semblable à la Figure 2
Figure 2 : Votre première liste de données !
Cliquer sur une cellule
Maintenant, nous allons rendre cette liste de données cliquable. Pour cela, il faut tout d’abord utiliser un contrôleur de navigation (UINavigationController) qui va permettre de gérer la navigation entre les différentes vues très simplement.
Modifiez votre application delegate pour obtenir ceci :
Dans le .h
#import <UIKit/UIKit.h>
#import "DataListViewController.h"
@interface
TableViewAppDelegate :
NSObject
<UIApplicationDelegate> {
DataListViewController *dataListViewController;
UINavigationController *navController;
}
@property
(
nonatomic
, retain)
IBOutlet
UIWindow *window;
@end
Dans le .m
- (
BOOL
)application:(UIApplication *)application didFinishLaunchingWithOptions:(
NSDictionary
*)launchOptions
{
dataListViewController = [[DataListViewController alloc] initWithStyle:UITableViewStylePlain];
navController = [[UINavigationController alloc] initWithRootViewController:dataListViewController];
// 1
[
self
.window addSubview:navController.view];
// 2
[
self
.window makeKeyAndVisible];
return
YES
;
}
- (
void
)dealloc
{
[navController release];
[dataListViewController release];
[_window release];
[
super
dealloc];
}
En 1, on alloue le contrôleur de navigation, avec comme rootViewController dataListViewController, puis on affiche la vue du navController ainsi alloué à la place de la vue de dataListViewController ligne 2.
Ensuite, il faut créer un nouveau contrôleur (UIViewController) que vous nommerez DetailListViewController (cochez With XIB for User Interface). Dans ce contrôleur, affichez un label :
Dans le .h
#import <UIKit/UIKit.h>
@interface
DetailListViewController : UIViewController {
IBOutlet
UILabel *label;
}
@property
(
nonatomic
, retain) UILabel *label;
@end
Dans le .m, ajoutez cette ligne
@synthesize
label;
Et n’oubliez pas le dealloc
- (
void
)dealloc
{
[label release];
[
super
dealloc];
}
Revenez à DataListViewController.m et rendez-vous à la méthode – (void)tableView:(UITableView *) tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath que vous implémenterez comme suit : (n’oubliez pas l’import de DetailListViewController.h)
- (
void
)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(
NSIndexPath
*)indexPath
{
DetailListViewController *detailViewController = [[DetailListViewController alloc] initWithNibName:@
"DetailListViewController"
bundle:
nil
];
[
self
.navigationController pushViewController:detailViewController animated:
YES
];
detailViewController.label.text = [dataToShow objectAtIndex:[indexPath row]];
detailViewController.title = @
"Détail"
;
[detailViewController release];
}
Maintenant, en cliquant sur une cellule, vous affichez une nouvelle vue. Libre à vous de la remplir comme vous le souhaitez !
Créer une cellule personnalisée
Pour finir avec les table view, nous allons voir comment créer une cellule personnalisée. Ajoutez un nouveau fichier, iOS > Cocoa Touch Classes > Objective-C class > subclass of UITableViewCell que vous nommerez CustomCell. Ensuite, modifiez ces nouveaux fichiers pour y ajouter un label :
Dans le .h
#import <UIKit/UIKit.h>
@interface
CustomCell : UITableViewCell {
UILabel *myLabel;
}
@property
(
nonatomic
, retain) UILabel *myLabel;
@end
Dans le .m
#import "CustomCell.h"
@implementation
CustomCell
@synthesize
myLabel;
- (
id
)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(
NSString
*)reuseIdentifier
{
self
= [
super
initWithStyle:style reuseIdentifier:reuseIdentifier];
if
(
self
) {
myLabel = [[UILabel alloc] initWithFrame:CGRectMake(150, 5, 120, 30)];
myLabel.font = [UIFont fontWithName:@
"zapfino"
size:12.0];
[
self
addSubview:myLabel];
}
return
self
;
}
- (
void
)setSelected:(
BOOL
)selected animated:(
BOOL
)animated
{
[
super
setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (
void
)dealloc
{
[myLabel release];
[
super
dealloc];
}
@end
Enfin, dans DataListViewController.m, ajouter l’import de CustomCell.h, puis modifiez la méthode cellForRowAtIndexPath comme suit :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(
NSIndexPath
*)indexPath
{
static
NSString
*CellIdentifier = @
"Cell"
;
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if
(cell ==
nil
) {
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.myLabel.text = [dataToShow objectAtIndex:indexPath.row];
return
cell;
}
Compilez et lancez, vous devriez obtenir une liste de données comme à la Figure 3.
Figure 3 : Une liste de cellules customisées
Une bonne chose de faite non ? Un petit café, ou alors continuez sur votre lancée !
Utiliser un picker view
Créez un nouveau projet Window-based Application, que vous nommerez Picker, pour utiliser les picker view.
Créez ensuite une nouvelle classe de type UIViewController que vous nommerez PickerViewController. Comme d’habitude, ajoutez la vue d’un objet PickerViewController (que vous aurez alloué dans votre application delegate) à la window.
Ensuite, dans le viewDidLoad de PickerViewController, ajoutez ceci :
- (
void
)viewDidLoad
{
[
super
viewDidLoad];
myPickerView = [[UIPickerView alloc] initWithFrame:CGRectZero];
// 1
CGSize pickerSize = [myPickerView sizeThatFits:CGSizeZero];
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
CGRect pickerRect = CGRectMake( 0.0,
screenRect.size.height - 84.0 - pickerSize.height,
pickerSize.width,
pickerSize.height);
myPickerView.frame = pickerRect;
// 2
myPickerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
myPickerView.showsSelectionIndicator =
YES
;
// 3
myPickerView.delegate =
self
;
// 4
myPickerView.dataSource =
self
;
// 5
[
self
.view addSubview:myPickerView];
label = [[UILabel alloc] initWithFrame:CGRectMake(10, 30, 200, 20)];
// 6
[
self
.view addSubview:label];
pickerViewArray = [[
NSArray
alloc] initWithObjects:@
"Element 1"
, @
"Element 2"
, @
"Element 3"
, @
"Element 4"
, @
"Element 5"
, @
"Element 6"
, @
"Element 7"
,
nil
];
// 7
}
La taille d’un picker view est optimisée. Comprenez que vous ne pouvez pas vraiment le dimensionner comme vous le souhaitez. C’est pourquoi de la ligne 1 à la ligne 2, vous trouverez un mécanisme qui optimise sa taille, et va le centrer sur votre vue.
Vous pouvez choisir d’afficher une sorte de vitre, vous montrant la ligne sélectionnée. Par défaut, rien ne s’affiche.
Ligne 3, nous choisissons donc de montrer à l’utilisateur la sélection actuelle.
Le picker view nécessite d’être rempli par des données, c’est pourquoi nous définissons le view controller actuel comme source de données ligne 5, données qui seront dans un tableau, initialisé ligne 7. La classe UIPickerView contient un protocole UIPickerViewDelegate. À la ligne 4, on définit donc self comme étant delegate du picker view.
Pour montrer le bon fonctionnement du picker, on ajoute un label à la vue ligne 6, qui affichera les éléments sélectionnés.
Comme nous venons de définir la classe PickerViewController comme étant à la fois source de données et delegate de UIPickerView, vous devez écrire ceci dans le .h :
@interface
PickerViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
Ensuite, rappelez-vous, un protocole définit des méthodes optionnelles et d’autres requises. Vous les trouverez dans la documentation.
Nous souhaitons afficher deux colonnes dans le picker, une contenant Element 1, Element 2, etc. et une autre contenant le numéro de la ligne.
Ajoutez donc ces méthodes dans PickerViewController.m :
#pragma mark -
#pragma mark UIPickerViewDelegate
- (
void
)pickerView:(UIPickerView *)pickerView didSelectRow:(
NSInteger
)row inComponent:(
NSInteger
)component
{
label.text = [
NSString
stringWithFormat:@
"%@ - %d"
, [pickerViewArray objectAtIndex:[pickerView selectedRowInComponent:0]], [myPickerView selectedRowInComponent:1]];
// 1
}
#pragma mark -
#pragma mark UIPickerViewDataSource
- (
NSString
*)pickerView:(UIPickerView *)pickerView titleForRow:(
NSInteger
)row forComponent:(
NSInteger
)component
{
NSString
*returnStr = @
""
;
if
(component == 0) {
returnStr = [pickerViewArray objectAtIndex:row];
// 2
}
else
{
returnStr = [[
NSNumber
numberWithInt:row] stringValue];
// 3
}
return
returnStr;
}
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(
NSInteger
) component {
CGFloat componentWidth = 0.0;
if
(component == 0)
componentWidth = 240.0;
// 4
else
componentWidth = 40.0;
// 5
return
componentWidth;
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(
NSInteger
)component {
return
40.0;
// 6
}
- (
NSInteger
)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(
NSInteger
)component
{
return
[pickerViewArray count];
// 7
}
- (
NSInteger
)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return
2;
// 8
}
Nous choisissons d’afficher deux colonnes dans le picker, grâce à la ligne 8. Lignes 4 et 5, on doit définir la taille pour chaque colonne (nommée ici component, celle numérotée 0 étant à gauche).
Ligne 6, on définit la hauteur des lignes, et ligne 7, on détermine leur nombre qui est défini par le nombre d’éléments du tableau pickerViewArray.
Pour remplir chaque ligne du picker, on implémente la méthode – (NSString *)pickerView:(UIPicker- View *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component. Pour la colonne de gauche (0), le titre de la ligne sera l’élément correspondant dans le tableau, ligne 2. Pour celle de droite, le titre le de ligne est son numéro, ligne 3.
Enfin, ligne 1, on affiche dans le label les éléments sélectionnés dans chaque colonne.
Voilà, ce tutoriel est maintenant terminé !!