Pelo que eu posso dizer, às vezes é realmente necessário subclasse UINavigationBar, para fazer algum restyling fora do padrão. Às vezes, é possível evitar ter que fazer isso usando categorias , mas nem sempre.
Atualmente, até onde eu sei, a única maneira de definir um UINavigationBar personalizado dentro de um UIViewController é via IB (ou seja, por meio de um arquivo) - provavelmente não deveria ser assim, mas por enquanto, temos que conviver com isso.
Isso geralmente é bom, mas às vezes o uso de IB não é realmente viável.
Então, eu vi três opções:
- Subclasse UINavigationBar e conecte tudo em IB, então muck sobre como carregar o bico cada vez que eu queria um UINavigationController,
- Use a substituição de método dentro de uma categoria para alterar o comportamento de UINavigationBar, ao invés de subclassificação, ou
- Subclasse UINavigationBar e faça uma pequena bagunça arquivando / desarquivando o UINavigationController.
A opção 1 era inviável (ou pelo menos chata demais) para mim neste caso, pois eu precisava criar o UINavigationController programaticamente, 2 é um pouco perigoso e mais uma opção de último recurso na minha opinião, então escolhi a opção 3.
Minha abordagem foi criar um arquivo de 'modelo' de um UINavigationController e desarquivá-lo, devolvendo-o initWithRootViewController
.
Veja como:
No IB, criei um UINavigationController com a classe apropriada definida para o UINavigationBar.
Então, peguei o controlador existente e salvei uma cópia arquivada dele usando +[NSKeyedArchiver archiveRootObject:toFile:]
. Acabei de fazer isso dentro do delegado do aplicativo, no simulador.
Em seguida, usei o utilitário 'xxd' com o sinalizador -i, para gerar o código c do arquivo salvo, para incorporar a versão arquivada em minha subclasse ( xxd -i path/to/file
).
Dentro, initWithRootViewController
eu desarquivo esse modelo e me coloco como o resultado do desarquivamento:
// 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];
}
Então, posso simplesmente pegar uma nova instância da minha subclasse UIViewController que tem a barra de navegação personalizada definida:
UIViewController *modalViewController = [[[CTNavigationController alloc] initWithRootViewController:myTableViewController] autorelease];
[self.navigationController presentModalViewController:modalViewController animated:YES];
Isso me dá um UITableViewController modal com uma barra de navegação e barra de ferramentas configuradas, e com a classe de barra de navegação personalizada no lugar. Não precisei fazer nenhuma substituição de método um pouco desagradável e não tenho que me preocupar com pontas quando na verdade quero apenas trabalhar programaticamente.
Eu gostaria de ver o equivalente de +layerClass
dentro de UINavigationController - +navigationBarClass
- mas, por enquanto, isso funciona.