Alguém sabe como posso usar minha subclasse customizada de UINavigationBar
se eu instanciar UINavigationController
programaticamente (sem IB)?
Arraste um UINavigationController
no IB para me mostrar um abaixo da barra de navegação e usando o Identity Inspectory posso alterar o tipo de classe e definir minha própria subclasse de, UINavigationBar
mas programaticamente não consigo, a navigationBar
propriedade do Navigation Controller é somente leitura ...
O que devo fazer para personalizar a barra de navegação de forma programática? O IB é mais "poderoso" do que "código"? Eu acreditava que tudo o que pode ser feito no IB também pode ser feito de forma programática.
Respostas:
Você não precisa mexer com o XIB, basta usar KVC.
fonte
Desde o iOS5, a apple fornece um método para fazer isso diretamente. Referência
fonte
A partir do iOS 4, você pode usar a
UINib
classe para ajudar a resolver esse problema.UINavigationBar
subclasse personalizada .UINavigationController
como o único objeto.UINavigationController
'sUINavigationBar
para sua subclasse personalizada.[navController setViewcontrollers[NSArray arrayWithObject:myRootVC]];
[navController pushViewController:myRootVC];
Em código:
Agora você tem um
UINavigationController
com o seu costumeUINavigationBar
.fonte
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:
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:Então, posso simplesmente pegar uma nova instância da minha subclasse UIViewController que tem a barra de navegação personalizada definida:
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.fonte
Eu uso a "opção 1"
Crie um arquivo nib com apenas o UINavigationController nele. E defina a classe UINavigationBar para minha classe personalizada.
fonte
A solução de Michael funciona, mas você pode evitar o NSKeyedArchiver e o utilitário 'xxd'. Simplesmente subclasse UINavigationController e substitua
initWithRootViewController
, carregando seu NIB de NavigationController personalizado diretamente:fonte
Atualização: Usar
object_SetClass()
não funciona mais como se iOS5 GM. Uma solução alternativa foi adicionada abaixo.Use NSKeyedUnarchiver para definir manualmente a classe de desarquivamento para a barra de navegação.
Nota: Esta solução original só funciona antes do iOS5:
Há uma ótima solução, que postei aqui - injete a subclasse navBar diretamente em sua visualização
UINavigationController
:fonte
Um cenário que descobri que precisamos usar subclasse em vez de categoria é definir a cor de fundo da barra de navegação com a imagem padrão, porque no iOS5 a substituição de drawRect usando categoria não funciona mais. Se você deseja oferecer suporte a ios3.1-5.0, a única maneira de fazer é criar uma subclasse da barra de navegação.
fonte
Esses métodos de categoria são perigosos e não para iniciantes. Além disso, a complicação de iOS4 e iOS5 serem diferentes, torna esta uma área que pode causar bugs para muitas pessoas. Aqui está uma subclasse simples que eu uso que oferece suporte a iOS4.0 ~ iOS6.0 e é muito simples.
.h
.m
fonte
Não é recomendado criar uma subclasse da
UINavigationBar
classe. A maneira preferida de personalizar a barra de navegação é definir suas propriedades para fazê-la aparecer como você deseja e usar visualizações personalizadas dentro de UIBarButtonItems junto com um delegado para obter o comportamento desejado.O que você está tentando fazer que precisa de uma subclasse?
Além disso, não acho que o IB esteja realmente substituindo a barra de navegação. Tenho certeza que ele simplesmente não está exibindo o padrão e tem sua barra de navegação personalizada como uma subvisualização. Se você chamar UINavigationController.navigationBar, você obtém uma instância de sua barra?
fonte
Se você deseja criar uma subclasse de navBar apenas para alterar a imagem de fundo - não há necessidade no iOS 5. Haverá um método como este setBackgroundImage
fonte
setBackgroundImage:forBarMetrics:
conforme descrito aqui: developer.apple.com/library/IOS/#documentation/UIKit/Reference/…Na sequência do comentário de obb64, acabei usando seu truque com
setViewControllers:animated:
para definir o controlador como orootController
para onavigationController
carregado da ponta. Este é o código que estou usando:fonte