Per quanto ne so, a volte è davvero necessario sottoclassare UINavigationBar, per fare un restyling non standard. A volte è possibile evitare di doverlo fare utilizzando le categorie , ma non sempre.
Attualmente, per quanto ne so, l' unico modo per impostare una UINavigationBar personalizzata all'interno di un UIViewController è tramite IB (cioè tramite un archivio) - probabilmente non dovrebbe essere così, ma per ora, dobbiamo conviverci.
Questo spesso va bene, ma a volte l'uso di IB non è realmente fattibile.
Quindi, ho visto tre opzioni:
- Sottoclasse UINavigationBar e aggancia il tutto in IB, quindi muck circa il caricamento del pennino ogni volta che volevo un UINavigationController,
- Utilizzare la sostituzione del metodo all'interno di una categoria per modificare il comportamento di UINavigationBar, anziché creare sottoclassi o
- Sottoclasse UINavigationBar e fai un po 'di confusione con l'archiviazione / annullamento dell'archiviazione di UINavigationController.
L'opzione 1 era irrealizzabile (o almeno troppo fastidiosa) per me in questo caso, poiché avevo bisogno di creare l'UINavigationController a livello di programmazione, 2 è un po 'pericolosa e più di un'opzione di ultima istanza secondo me, quindi ho scelto l'opzione 3.
Il mio approccio consisteva nel creare un archivio "modello" di un UINavigationController e disarchiviarlo, restituendolo in initWithRootViewController
.
Ecco come:
In IB, ho creato un UINavigationController con la classe appropriata impostata per UINavigationBar.
Quindi, ho preso il controller esistente e ne ho salvato una copia archiviata utilizzando +[NSKeyedArchiver archiveRootObject:toFile:]
. L'ho appena fatto all'interno del delegato dell'app, nel simulatore.
Ho quindi utilizzato l'utility 'xxd' con il flag -i, per generare il codice c dal file salvato, per incorporare la versione archiviata nella mia sottoclasse ( xxd -i path/to/file
).
All'interno initWithRootViewController
disarchivo quel modello e mi imposto al risultato dell'annullamento dell'archiviazione:
// 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];
}
Quindi, posso semplicemente prendere una nuova istanza della mia sottoclasse UIViewController che ha la barra di navigazione personalizzata impostata:
UIViewController *modalViewController = [[[CTNavigationController alloc] initWithRootViewController:myTableViewController] autorelease];
[self.navigationController presentModalViewController:modalViewController animated:YES];
Questo mi dà un UITableViewController modale con una barra di navigazione e una barra degli strumenti tutte impostate e con la classe della barra di navigazione personalizzata in posizione. Non ho avuto bisogno di sostituire un metodo leggermente sgradevole, e non devo perdere tempo con i pennini quando voglio solo lavorare in modo programmatico.
Mi piacerebbe vedere l'equivalente +layerClass
all'interno di UINavigationController - +navigationBarClass
- ma per ora funziona.