iphone - bottom - status bar ios
Fondo personalizado UINavigationBar (15)
Acabo de encontrar esta entrada de blog, describiendo este tema muy simple: http://web0.at/blog/?p=38
me ayudó mucho, usan el método "drawRect" para obtener la personalización del fondo.
He intentado configurar un fondo personalizado para toda mi NavigationBar (no solo titleView), pero he estado luchando.
Encontré este hilo
http://discussions.apple.com/thread.jspa?threadID=1649012&tstart=0
Pero no estoy seguro de cómo implementar el fragmento de código que se proporciona. ¿El código se implementa como una nueva clase? Además, ¿dónde instalo el UINavigationController
ya que tengo una aplicación creada con la plantilla de NavigationView por lo que no está hecha en mi controlador raíz como en el ejemplo
Aquí hay una solución alternativa que le permite usar su propia subclase personalizada de UINavigationBar:
Como Apple mismo dijo, no es correcto anular los métodos en las Categorías. Entonces, la mejor manera de personalizar el fondo de UINavigarionBar
es UINavigarionBar
subclase y anular -(void)drawInRect:
method.
@implementation AppNavigationBar
- (void)drawRect:(CGRect)rect
{
UIImage *patternImage = [UIImage imageNamed:@"image_name.png"];
[patternImage drawInRect:rect];
}
Para usar esta UINavigationBar
personalizada, debe establecerse como la propiedad navigationBar
de su UINavigationBarController
. Como usted sabe, esta propiedad es de solo lectura. Entonces, ¿qué se debe hacer es:
- (void)viewDidLoad
{
[super viewDidLoad];
AppNavigationBar *nav = [AppNavigationBar new];
[self setValue:nav forKey:@"navigationBar"];
}
Funciona tanto para iOS 5 como para 4.3.
Debe usar el proxy ''apariencia'' para cambiar el fondo y otras propiedades de estilo de controles como UINavigationBar
, UIToolBar
, etc. en iOS 5.xx. Sin embargo, estos no están disponibles para iOS 4.xx, por lo que para compatibilidad con versiones anteriores, necesita una solución híbrida.
Si desea admitir dispositivos iOS 4.xx e iOS 5.xx (es decir, su DeploymentTarget
es 4.xx), debe tener cuidado al ajustar la llamada al proxy de apariencia comprobando en tiempo de ejecución si el selector ''apariencia'' está presente o no.
Puedes hacerlo así:
//Customize the look of the UINavBar for iOS5 devices
if ([[UINavigationBar class]respondsToSelector:@selector(appearance)]) {
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"NavigationBar.png"] forBarMetrics:UIBarMetricsDefault];
}
También debe dejar la solución iOS 4.xx que puede haber implementado. Si ha implementado la solución drawRect
para dispositivos iOS 4.xx, como lo menciona @ludwigschubert, debe dejar eso en:
@implementation UINavigationBar (BackgroundImage)
//This overridden implementation will patch up the NavBar with a custom Image instead of the title
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: @"NavigationBar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end
Esto hará que el NavBar
vea igual en dispositivos iOS 4 e iOS 5.
El problema que tendrá es que si utiliza un controlador de navegación, el título de cada página se superpondrá a su barra de navegación personalizada. Si su barra de navegación contiene un logotipo o el nombre de su aplicación, esto es obviamente inaceptable.
Puede establecer el título de cada vista en su pila de navegación en blanco, pero algunas vistas fuerzan un título del que no puede hacer nada (como el selector de fotografías). Por lo tanto, es posible que desee crear una imagen de barra de navegación alternativa con el mismo color o diseño que la barra de navegación del logotipo, pero con un área en blanco para dejar espacio para los títulos superpuestos.
Para cambiar las imágenes de la barra de navegación a voluntad, agregue una propiedad al delegado de su aplicación para mantener el nombre de la imagen de la barra de navegación y reemplace la primera línea del primer ejemplo anterior con estas dos:
YourAppDelegate* theApp = (YourAppDelegate*)[[UIApplication sharedApplication] delegate];
UIImage* image = [UIImage imageNamed:theApp.navBarName];
Luego, en el primer controlador de vista que insertarás en la pila de navegación, haz algo como esto:
- (void)viewWillAppear:(BOOL)animated
{
YourAppDelegate* theApp = (YourAppDelegate*)[[UIApplication sharedApplication] delegate];
theApp.navBarName = @"navBar_plain";
}
Luego, en el controlador de vista raíz, haga lo mismo pero especifique la imagen de la barra de navegación con el logotipo, para que se restaure cuando el usuario vuelva a navegar y no haya ningún título en conflicto.
En iOS5, se zPosition
valor zPosition
(de UINavigationBar''s
capa más profunda de UINavigationBar''s
). Entonces, si cambias esa zPosition
, la antigua funciona.
p.ej.
UINavigationBar *_bar = navigationController.navigationBar;
// Insert ImageView
UIImage *_img = [UIImage imageNamed:@"navibar.png"];
UIImageView *_imgv = [[[UIImageView alloc] initWithImage:_img] autorelease];
_imgv.frame = _bar.bounds;
UIView *v = [[_bar subviews] objectAtIndex:0];
v.layer.zPosition = -FLT_MAX;
_imgv.layer.zPosition = -FLT_MAX+1;
[_bar insertSubview:_imgv atIndex:1];
Este script controla la capa de la vista, por lo que debe importar QuartzCore
.
Implementar una categoría no es recomendable. iOS5 puede proporcionar alivio para este problema. Pero para las antiguas API, puedes:
- Subclase
UINavigationBar
para decirCustomNavBar
e implementar el drawRect personalizado de la respuesta de Lithium. - Para todos los
UINavigationControllers
basados en IB, proporcioneCustomNavBar
como clase personalizada para suUINavigationBar
. - Para todos los
UINavigationControllers
basados en código. Crea un XIB con unUINavigationController
y haz el paso dos. A continuación, proporcione un método de fábrica en el código que carga elUINavigationController
desde el plumín y proporciona unIBOutlet
.
P.ej.
[[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil];
UINavigationController *navController = self.customNavigationController;
navController.viewControllers = [NSArray arrayWithObject:controller]
La implementación de una categoría no funcionará en iOS5, debe usar los consejos de Uddhav Kambli para usar CustomNavbar en iOS ≤ 5.
Otro enfoque es Usar el delegado de UINavigationController. No requiere subclassing / overwriting de la clase UINavigationBar:
/*
in the place where you init the navigationController:
fixer = [[AENavigationControllerDelegate alloc] init];
navigationController.delegate = fixer;
*/
@interface AENavigationControllerDelegate : NSObject <UINavigationControllerDelegate>
@end
@implementation AENavigationControllerDelegate
#define bgImageTag 143
- (void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
//this is for the future for implementing with the appearance api:
if ([[navigationController navigationBar] respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)])
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[navigationController navigationBar] setBackgroundImage:[UIImage imageNamed:@"header-logo-bg.png"]
forBarMetrics:UIBarMetricsDefault];
});
}
else
{
UIImageView* imageView = (UIImageView*)[navigationController.navigationBar viewWithTag:bgImageTag];
if(!imageView)
{
UIImage *image = [UIImage imageNamed:@"header-logo-bg.png"];
imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
imageView.tag = bgImageTag;
}
[navigationController.navigationBar insertSubview:imageView atIndex:0];
}
}
@end
Para todos aquellos que tengan problemas con los fondos personalizados de UINavigationBar en iOS5, hagan esto en los métodos viewDidLoad correspondientes:
#if defined(__IPHONE_5_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0
if ([self.navigationController.navigationBar respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"TitleBar"] forBarMetrics:UIBarMetricsDefault];
}
#endif
Tenga en cuenta que en mi caso, la imagen de fondo se llamaba "Barra de título". Puede poner el nombre de su imagen de fondo personalizada.
Para una vista estática (sin animación en absoluto), utilizo iOS setBackgroundImage predeterminado
Pero cuando tengo una vista animada (cambiar el tamaño lo más probable), creo un UIImageView personalizado y lo agrego a la barra de navegación para que tenga más flexibilidad sobre él
El asunto es que si lo agregas, se colocará encima de los botones y de titleView, así que guardo manualmente una copia de la mayoría de las subvistas, las eliminé de la vista principal, agregué mi imageView y luego volví a agregar todas las subvistas
Esto funciona para mí
UIImageView *navBackground = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"navigationBackgroundSample.jpg"]];
UIView *tempTitleView = [[self.navigationBar.subviews objectAtIndex:1] autorelease];
[[self.navigationBar.subviews objectAtIndex:1] removeFromSuperview];
[self.navigationBar addSubview:navBackground];
[self.navigationBar addSubview:tempTitleView];
self.navigationBar.clipsToBounds = YES;
[navBackground release];
En este caso, no tengo botones y descubrí que mi titleView está en el índice 1, si tienes botones, deberían estar en algún lugar de la matriz de subvistas de navigationBar
No sé qué hay en el índice 0, no sé si esto puede funcionar en el caso de que tenga el título del texto tampoco ...
Puede subclase UINavigationBar y habilitarlo así, ya que las categorías para drawRect ya no funcionarán en iOS5
navigationController = [[((^ {
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:[NSKeyedArchiver archivedDataWithRootObject:navigationController]];
[unarchiver setClass:[SAPHUINavigationBar class] forClassName:@"UINavigationBar"];
[unarchiver setClass:[UIViewController class] forClassName:NSStringFromClass([navigationController.topViewController class])];
return unarchiver;
})()) decodeObjectForKey:@"root"] initWithRootViewController:navigationController.topViewController];
Solo tienes que sobrecargar drawRect así:
@implementation UINavigationBar (CustomImage)
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: @"NavigationBar.png"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end
También puede anular el drawLayer:inContext:
en una clase de categoría UINavigationBar
. Dentro del drawLayer:inContext:
puede dibujar la imagen de fondo que desea usar.
- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
if ([self isMemberOfClass:[UINavigationBar class]] == NO) {
return;
}
UIImage *image = (self.frame.size.width > 320) ?
[UINavigationBar bgImageLandscape] : [UINavigationBar bgImagePortrait];
CGContextClip(context);
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image.CGImage);
}
Y como un proyecto completo de demostración de Xcode para personalizar la apariencia de UINavigationBar
this y this podrían ser útiles.
Uddhav y leflaw tienen razón. Este código funciona bien:
@interface CustomNavigationBar : UINavigationBar
@end
@implementation CustomNavigationBar
-(void) drawRect:(CGRect)rect
{
UIImage *image = [UIImage imageNamed: @"myNavBarImage"];
[image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
}
@end
// this can go anywhere
+(UINavigationController*) myCustomNavigationController
{
MyViewController *vc = [[[MyViewController alloc] init] autorelease];
UINavigationController *nav = [[[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil] objectAtIndex:0];
nav.viewControllers = [NSArray arrayWithObject:vc];
return nav;
}
Tienes que crear CustomNavigationController.xib y poner un UINavigationController en él y cambiar la clase de navigationBar a "CustomNavigationBar".