Pour autant que je sache, il est parfois en effet nécessaire de sous-classer UINavigationBar, de faire un restyling non standard. Il est parfois possible d'éviter d'avoir à le faire en utilisant des catégories , mais pas toujours.
Actuellement, pour autant que je sache, le seul moyen de définir une UINavigationBar personnalisée dans un UIViewController est via IB (c'est-à-dire via une archive) - cela ne devrait probablement pas être ainsi, mais pour l'instant, nous devons vivre avec.
C'est souvent bien, mais parfois utiliser IB n'est pas vraiment faisable.
Donc, j'ai vu trois options:
- Sous-classe UINavigationBar et branchez tout dans IB, puis muck de charger la plume chaque fois que je voulais un UINavigationController,
- Utilisez le remplacement de méthode dans une catégorie pour modifier le comportement de UINavigationBar, plutôt que de sous-classer, ou
- Sous-classe UINavigationBar et faites un peu de travail avec l'archivage / désarchivage de UINavigationController.
L'option 1 était irréalisable (ou du moins trop ennuyeuse) pour moi dans ce cas, car je devais créer le UINavigationController par programme, 2 est un peu dangereuse et plutôt une option de dernier recours à mon avis, j'ai donc choisi l'option 3.
Mon approche consistait à créer une archive `` modèle '' d'un UINavigationController et à la désarchiver, en la renvoyant dans initWithRootViewController
.
Voici comment:
Dans IB, j'ai créé un UINavigationController avec l'ensemble de classes approprié pour UINavigationBar.
Ensuite, j'ai pris le contrôleur existant et en ai enregistré une copie archivée à l'aide de +[NSKeyedArchiver archiveRootObject:toFile:]
. Je viens de faire cela dans le délégué de l'application, dans le simulateur.
J'ai ensuite utilisé l'utilitaire 'xxd' avec l'indicateur -i, pour générer du code c à partir du fichier enregistré, pour intégrer la version archivée dans ma sous-classe ( xxd -i path/to/file
).
Dans initWithRootViewController
je désarchive ce modèle et je me fixe au résultat de la désarchivage:
// This is the data from [NSKeyedArchiver archivedDataWithRootObject:controller], where
// controller is a CTNavigationController with navigation bar class set to CTNavigationBar,
// from IB. This c code was created using 'xxd -i'
static unsigned char archived_controller[] = {
0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03,
...
};
static unsigned int archived_controller_len = 682;
...
- (id)initWithRootViewController:(UIViewController *)rootViewController {
// Replace with unarchived view controller, necessary for the custom navigation bar
[self release];
self = (CTNavigationController*)[NSKeyedUnarchiver unarchiveObjectWithData:[NSData dataWithBytes:archived_controller length:archived_controller_len]];
[self setViewControllers:[NSArray arrayWithObject:rootViewController]];
return [self retain];
}
Ensuite, je peux simplement récupérer une nouvelle instance de ma sous-classe UIViewController qui a la barre de navigation personnalisée définie:
UIViewController *modalViewController = [[[CTNavigationController alloc] initWithRootViewController:myTableViewController] autorelease];
[self.navigationController presentModalViewController:modalViewController animated:YES];
Cela me donne un UITableViewController modal avec une barre de navigation et une barre d'outils configurées, et avec la classe de barre de navigation personnalisée en place. Je n'avais pas besoin de faire de remplacement de méthode légèrement désagréable, et je n'ai pas à me soucier des plumes quand je veux vraiment travailler de manière programmatique.
Je voudrais voir l'équivalent de +layerClass
dans UINavigationController - +navigationBarClass
- mais pour l'instant, cela fonctionne.