change - Alcanzar colores vivos y brillantes para una UINavigationBar translĂșcida iOS 7
navigation item swift (16)
¿Hay alguna manera de usar la solución @aprato sin subclasificar UINavigationBar?
En mi proyecto, mi vista principal es un UIViewController.
el problema es que el navigationController es una propiedad de solo lectura, ¿hay alguna manera de usar tu clase con mi proyecto porque no puedo usar: [[UINavigationController alloc] initWithNavigationBarClass:
Gracias
ACTUALIZACIÓN DE iOS 7.1 : Parece que la solución para modificar el canal alfa en UINavigationBar se ha ignorado en esta actualización. En este momento, la mejor solución parece ser ''lidiar con eso'' y esperar que cualquier color que elija pueda tener un efecto translúcido. Todavía estoy buscando formas de evitar esto.
ACTUALIZACIÓN DE iOS 7.0.3 : La biblioteca de GitHub que creamos se ha actualizado para solucionar este problema al usar iOS 7.0.3. Desafortunadamente, no existe una fórmula mágica para admitir ambos colores creados en iOS 7.0.2 y versiones anteriores e iOS 7.0.3. Parece que Apple mejoró la saturación, pero a costa de la opacidad (ya que la translucidez borrosa depende del nivel de opacidad). Yo, junto con algunos otros, estamos trabajando para crear una solución mucho mejor para esto.
Estoy seguro de que muchas personas ya han encontrado el problema donde iOS 7 tiende a desaturar el color de una UINavigationBar que es translúcida.
Mi objetivo es lograr un UINavigationBar con este color de tinte, pero translúcido:
Sin embargo, con translucidez, estoy obteniendo esto. La vista de fondo es blanca, lo cual entiendo que hará que esta vista sea un poco más clara:
¿Hay alguna manera de lograr el color original sin dejar de tener translucidez? Me di cuenta de que Facebook ha podido conseguir que su barra sea su color azul intenso, como se muestra aquí:
..so sé que tiene que haber alguna forma. Las vistas de fondo obviamente hacen una diferencia aquí, pero la mayor parte de su contenido también es gris / blanco. Parece que independientemente del color de tinte de barra que pongas, no puedes obtener colores vivos bajo translucidez.
Actualizado con la solución
Aquí está la solución con la que terminé. aprato la solución de aprato y luego UINavigationBar
el UINavigationBar
personalizado dentro de una subclase UINavigationController
. Creé un repositorio que incluye esta implementación, junto con una aplicación de ejemplo .
////////////////////////////
// CRNavigationBar.m
////////////////////////////
#import "CRNavigationBar.h"
@interface CRNavigationBar ()
@property (nonatomic, strong) CALayer *colorLayer;
@end
@implementation CRNavigationBar
static CGFloat const kDefaultColorLayerOpacity = 0.5f;
static CGFloat const kSpaceToCoverStatusBars = 20.0f;
- (void)setBarTintColor:(UIColor *)barTintColor {
[super setBarTintColor:barTintColor];
if (self.colorLayer == nil) {
self.colorLayer = [CALayer layer];
self.colorLayer.opacity = kDefaultColorLayerOpacity;
[self.layer addSublayer:self.colorLayer];
}
self.colorLayer.backgroundColor = barTintColor.CGColor;
}
- (void)layoutSubviews {
[super layoutSubviews];
if (self.colorLayer != nil) {
self.colorLayer.frame = CGRectMake(0, 0 - kSpaceToCoverStatusBars, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + kSpaceToCoverStatusBars);
[self.layer insertSublayer:self.colorLayer atIndex:1];
}
}
@end
////////////////////////////
// CRNavigationController.m
////////////////////////////
#import "CRNavigationController.h"
#import "CRNavigationBar.h"
@interface CRNavigationController ()
@end
@implementation CRNavigationController
- (id)init {
self = [super initWithNavigationBarClass:[CRNavigationBar class] toolbarClass:nil];
if(self) {
// Custom initialization here, if needed.
}
return self;
}
- (id)initWithRootViewController:(UIViewController *)rootViewController {
self = [super initWithNavigationBarClass:[CRNavigationBar class] toolbarClass:nil];
if(self) {
self.viewControllers = @[rootViewController];
}
return self;
}
@end
Como @bernhard mencionado anteriormente , es posible saturar el color del tinte de la barra para obtener la apariencia deseada de la barra de navegación.
Escribí una utilidad BarTintColorOptimizer para ese tipo de ajuste. Optimiza el color del tinte de la barra translúcida para que el color real de la barra coincida con el color deseado en iOS 7.xy posterior. Mire esta respuesta para más detalles.
El comportamiento de tintColor para barras ha cambiado en iOS 7.0. Ya no afecta el fondo de la barra y se comporta como se describe para la propiedad tintColor agregada a UIView. Para matizar los antecedentes del compás, utilice -barTintColor.Puede usar el siguiente código para que la aplicación funcione tanto con iOS6 como con iOS7.
if(IS_IOS7)
{
self.navigationController.navigationBar.barTintColor = [UIColor blackColor];
self.navigationController.navigationBar.translucent = NO;
}
else
{
self.navigationController.navigationBar.tintColor = [UIColor blackColor];
}
IS_IOS7 es una macro que se define en el archivo pch de la siguiente manera.
#define IS_IOS7 ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
El problema ahora ha sido solucionado por Apple en la nueva versión 7.0.3.
En lugar de crear su objeto UIColor en formato RGB , use HSB y aumente el parámetro de saturación. (Créditos a Sam Soffes quien describe este método here )
navigationBar.barTintColor = [UIColor colorWithHue:0.555f saturation:1.f brightness:0.855f alpha:1.f];
Nota: Esta solución es una compensación y no funciona bien para colores con alta saturación.
Para elegir el color HSB de su diseño, puede usar una herramienta como ColorSnapper que le permite simplemente copiar el formato UIColor HSB.
También puede probar la Categoría UIColor ( GitHub Link ) de David Keegan para modificar los colores existentes.
En una nota relacionada, puede establecer el color del texto del título (con sombra) fácilmente a través de:
NSShadow *titleShadow = [[NSShadow alloc] init];
titleShadow.shadowOffset = CGSizeMake(0.0f, -1.0f);
titleShadow.shadowColor = [UIColor blackColor];
NSDictionary *navbarTitleTextAttributes = @{NSForegroundColorAttributeName: [UIColor whiteColor],
NSShadowAttributeName: titleShadow};
[[UINavigationBar appearance] setTitleTextAttributes:navbarTitleTextAttributes];
Hablando francamente, las respuestas anteriores pueden ser correctas, pero seguir el truco funcionó para mí con mucha facilidad.
// this is complete 100% transparent image
self.imageBlack = [[UIImage imageNamed:@"0102_BlackNavBG"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2)
resizingMode:UIImageResizingModeStretch];
// this is non-transparent but iOS7
// will by default make it transparent (if translucent is set to YES)
self.imageRed = [[UIImage imageNamed:@"0102_RedNavBG"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2)
resizingMode:UIImageResizingModeStretch];
// some navigation controller
[nvCtrLeft.navigationBar setBackgroundImage:self.imageRed
forBarMetrics:UIBarMetricsDefault];
// some another navigation controller
[nvCtrCenter.navigationBar setBackgroundImage:self.imageRed
forBarMetrics:UIBarMetricsDefault];
Aquí están las imágenes utilizadas para self.imageRed
y self.imageBlack
.
< > la imagen negra está en este paréntesis no será visible ya que es transparente :)
< > la imagen roja está en este paréntesis.
Hay un gran reemplazo Dropin UINavigationController disponible de Simon Booth disponible en GitHub Aquí GitHub - C360NavigationBar
Si está retrocediendo con iOS6, verifique el controlador de la vista raíz como tal:
PatientListTableViewController * frontViewController = [[PatientListTableViewController alloc] init];
UINavigationController *navViewController = [[UINavigationController alloc] initWithNavigationBarClass:[C360NavigationBar class] toolbarClass:nil];
if ([navViewController.view respondsToSelector:@selector(setTintColor:)]) {
//iOS7
[navViewController.view setTintColor:self.navBarTintColor];
[[C360NavigationBar appearance] setItemTintColor:self.navBarItemTintColor];
} else {
//iOS6
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
navViewController.navigationBar.tintColor = self.navBarTintColor;
}
[navViewController pushViewController:frontViewController animated:NO];
self.window.rootViewController = navViewController;
He mejorado tu código en mi fork: https://github.com/allenhsu/CRNavigationController
Con mi modificación, el color del resultado en la pantalla (recogido sobre fondo blanco) será exactamente el mismo valor pasado a setBarTintColor
. Creo que es una solución increíble.
Me encontré con este Q / A al intentar configurar una barra de navegación de color uniforme con la transparencia DISABLED en iOS 7.
Después de experimentar un rato con barTintColor, descubrí que una forma muy fácil de tener una barra de navegación opaca es hacer una sola imagen de píxel del color deseado, crear una imagen estirable y establecerla en el fondo. Imagen de la barra de navegación .
UIImage *singlePixelImage = [UIImage imageNamed:@"singlePixel.png"];
UIImage *resizableImage = [singlePixelImage resizableImageWithCapInsets:UIEdgeInsetsZero];
[navigationBar setBackgroundImage:resizableImage forBarMetrics:UIBarMetricsDefault];
Tres líneas de código, muy simple y funciona TANTO en iOS 6 como en iOS 7 (barTintColor no es compatible con iOS 6).
Ninguno de estos hacks son necesarios :). Simplemente establecido:
self.navigationController.navigationBar.translucent = NO;
Para iOS 7, la translucidez predeterminada se ha mantenido en VERDADERO.
No se me ocurrió esta solución, pero parece funcionar bastante bien. Acabo de agregarlo a viewDidLoad en mi subclase de UINavigationController.
Fuente: https://gist.github.com/alanzeino/6619253
// cheers to @stroughtonsmith for helping out with this one
UIColor *barColour = [UIColor colorWithRed:0.13f green:0.14f blue:0.15f alpha:1.00f];
UIView *colourView = [[UIView alloc] initWithFrame:CGRectMake(0.f, -20.f, 320.f, 64.f)];
colourView.opaque = NO;
colourView.alpha = .7f;
colourView.backgroundColor = barColour;
self.navigationBar.barTintColor = barColour;
[self.navigationBar.layer insertSublayer:colourView.layer atIndex:1];
Una forma de baja fidelidad probablemente UIView
una UIView
que es la altura de la barra de navegación en la parte superior de la vista detrás de la barra. Haga que esa vista tenga el mismo color que la barra de navegación pero juegue con el alfa hasta que obtenga los efectos deseados:
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.navigationController.navigationBar.frame), 64)];
backgroundView.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:1 alpha:.5];
[self.navigationController.view insertSubview:backgroundView belowSubview:self.navigationController.navigationBar];
UIView detrás
(Se cambió el color de los ejemplos más bajos a la transparencia de énfasis. La transparencia / el desenfoque es más notorio cuando se está en movimiento).
UINavigationBar
el UINavigationBar
y colocar esa misma vista por encima del fondo, pero detrás de todo lo demás, probablemente logre resultados similares aunque sea menos hacky.
Otra solución que he visto es jugar con el alfa de UINavigationBar
:
self.navigationController.navigationBar.alpha = 0.5f;
Editar: en realidad, después de las pruebas parece que esto no proporciona el comportamiento previsto (ni ningún comportamiento):
.8 alfa
Alfa sin ajustar
Obviamente, solo querrás hacer esto en dispositivos iOS 7. Por lo tanto, agregue algún control de versión antes de implementar cualquiera de estos.
Una forma fácil de obtener el color que desea es usar
[<NAVIGATION_BAR> setBackgroundImage:<UIIMAGE> forBarPosition:<UIBARPOSITION> barMetrics:<UIBARMETRICS>];
Siempre que su imagen tenga algo de alfa, la translucidez funcionará y podrá configurar el alfa cambiando la imagen. Esto fue agregado en iOS7. El ancho y alto de la imagen son 640x88px para vertical (agregue 20 a 88 si desea que esté debajo de la barra de estado).
Utilicé la solución de @ aprato pero encontré algunos casos de esquina donde las nuevas capas de nuevos VC (por ejemplo, UINavigationItemButtonViews
, UINavigationItemViews
, etc.) se insertarían automáticamente en una posición debajo del extraColorLayer
(lo que causaría que esos elementos de título o botón se vean afectados por el extraColorLayer
y por lo tanto, de color más débil de lo que normalmente sería). Así que ajusté la solución de @ aprato para forzar que el extraColorLayer
permanezca en la posición de índice 1. En la posición de índice 1, el extraColorLayer
permanece justo encima del _UINavigationBarBackground
, pero debajo de todo lo demás.
Aquí está mi implementación de clase:
- (void)setBarTintColor:(UIColor *)barTintColor
{
[super setBarTintColor:barTintColor];
if (self.extraColorLayer == nil)
{
self.extraColorLayer = [CALayer layer];
self.extraColorLayer.opacity = kDefaultColorLayerOpacity;
[self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear
}
self.extraColorLayer.backgroundColor = barTintColor.CGColor;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.extraColorLayer != nil)
{
self.extraColorLayer.frame = CGRectMake(0, 0 - kSpaceToCoverStatusBars, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + kSpaceToCoverStatusBars);
}
}
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview
{
[super insertSubview:view aboveSubview:siblingSubview];
[self.extraColorLayer removeFromSuperlayer];
[self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear
}
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index
{
[super insertSubview:view atIndex:index];
[self.extraColorLayer removeFromSuperlayer];
[self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear
}
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview
{
[super insertSubview:view belowSubview:siblingSubview];
[self.extraColorLayer removeFromSuperlayer];
[self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear
}
ACTUALIZACIÓN DE iOS 7.0.3: Como ve arriba, 7.0.3 cambió las cosas. He actualizado mi esencia. Con suerte, esto desaparecerá a medida que las personas mejoren.
Respuesta original: Terminé con un truco combinando las otras dos respuestas. Estoy subclasificando UINavigationBar y agregando una capa en la parte posterior con algo de espacio extra para cubrir si alguna de las diversas barras de estado de altura están activas. La capa se ajusta en las subvistas de diseño y el color cambia siempre que establezca barTintColor.
Gist: https://gist.github.com/aprato/6631390
setBarTintColor
[super setBarTintColor:barTintColor];
if (self.extraColorLayer == nil) {
self.extraColorLayer = [CALayer layer];
self.extraColorLayer.opacity = self.extraColorLayerOpacity;
[self.layer addSublayer:self.extraColorLayer];
}
self.extraColorLayer.backgroundColor = barTintColor.CGColor;
layoutSubviews
[super layoutSubviews];
if (self.extraColorLayer != nil) {
[self.extraColorLayer removeFromSuperlayer];
self.extraColorLayer.opacity = self.extraColorLayerOpacity;
[self.layer insertSublayer:self.extraColorLayer atIndex:1];
CGFloat spaceAboveBar = self.frame.origin.y;
self.extraColorLayer.frame = CGRectMake(0, 0 - spaceAboveBar, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + spaceAboveBar);
}