Logrando colores vivos e intensos para un iOS 7 translúcido UINavigationBar


172

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 producir 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 actualizó para solucionar este problema cuando se usa 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, estoy trabajando para crear una solución mucho mejor para esto.


Estoy seguro de que muchas personas ya se han encontrado con el problema de que iOS 7 tiende a desaturar el color de un UINavigationBar que es translúcido.

Mi objetivo es lograr una UINavigationBar con este color de tinte, pero translúcido:

UINavigationBar, Opaque

Sin embargo, con translucidez, estoy entendiendo esto. La vista de fondo es blanca, lo que entiendo hará que esta vista sea un poco más clara:

UINavigationBar, translúcido

¿Hay alguna forma de lograr el color original sin dejar de ser translúcido? Me di cuenta de que Facebook ha podido hacer que su barra tenga su rico color azul, como se muestra aquí:

Facebook UINavigationBar, translúcido

..so sé que tiene que haber alguna manera. Las vistas de fondo obviamente marcan la diferencia aquí, pero la mayor parte de su contenido también es gris / blanco. Parece que independientemente del color de tinte de barra que coloque, no puede obtener colores vivos bajo translucidez.

Actualizado con solución.

Aquí está la solución que terminé ideando. Tomé aprato solución 's y luego abarcado la costumbre UINavigationBardentro de una UINavigationControllersubclase. He creado un repositorio que tiene esta implementación enumerada a continuació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

¿No es UINAvigationBaropaco Facebook iOS7 ?
Vinzzz

No, es una transparencia mucho más sutil que el iOS predeterminado. Mucho mejor, OMI.
Kevin

Barra de navegación de Facebook no transparente
LE SANG

77
Definitivamente es translúcido; por favor vea mi respuesta editada
SpacePyro

2
@Odelya: esta no es una solución para obtener los colores correctos, sino una solución para corregir la claridad de la UINavigationBarmejor manera posible cuando se expone a la translucidez en iOS 7.
SpacePyro

Respuestas:


52

ACTUALIZACIÓN DE iOS 7.0.3: Como ve arriba, 7.0.3 cambió las cosas. He actualizado mi esencia. Esperemos que esto desaparezca a medida que la gente se actualice.

Respuesta original: Terminé con un truco que combinaba las otras dos respuestas. Estoy subclasificando UINavigationBar y agregando una capa en la parte posterior con algo de espacio adicional para cubrir si alguna de las varias barras de estado de altura está activa. La capa se ajusta en subvistas de diseño y el color cambia cada vez que configura 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);
  }

¿Dónde implementó esto en el ViewController? Bajo viewDidLoad?
Jeremy

Esto funciona muy bien! Decidí agregar esto a mi UINavigationControllersubclase. Aquí hay una idea general para aquellos que estén interesados ​​en tener una costumbre UINavigationBardentro de a UINavigationController.
SpacePyro

@Jeremy como SpacePyro Tengo una subclase de controlador de navegación (que al igual que la barra que estaba usando pre 7 para la orientación de apariencia UIA) que anula el initWithRootViewControlleruso de esto. He actualizado mi esencia
Anthony

Um ... bueno ... creo que necesito ver esto en un proyecto de prueba completo para ver a qué te refieres. Pude replicar el ejemplo de timeuser a continuación, pero todavía estoy un poco verde con este.
Jeremy

1
@ Mr.T ¡Gracias! Cuando escribí que no estaba presionando todavía :) Pero lo actualicé ahora, agregué UIAppearance para la opacidad y el soporte para NSCoding
Anthony

10

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 teñir el fondo de la barra, use -barTintColor. Puede usar el siguiente código para que la aplicación funcione con ios6 y 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)

9

No se me ocurrió esta solución, pero parece funcionar bastante bien. Lo acabo de agregar 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];

1
Parece que después de presionar un nuevo controlador de vista en el controlador de navegación, cualquier elemento del botón de barra se mueve para estar debajo de esta capa de transparencia.
Evan Davis

Los títulos también quedan oscurecidos por esta capa de transparencia.
Nick Locking

Escribí esta esencia. Los comentarios son correctos; o bien los elementos del botón se presionan debajo cuando se presiona un nuevo controlador de vista, o las subcapas heredan el alfa de colourView. Bifurqué la otra respuesta y arreglé algunas cosas en una nueva clase: github.com/alanzeino/AZColoredNavigationBar
Alan Zeino

Pude poner el texto en blanco seleccionando el estilo de la Barra de navegación negra translúcida ... esto fue el truco para mí. También configure yourBar.tintColor = [UIColor whiteColor]; para otros botones personalizados en la parte superior.
Juan Zamora

6

Una forma de baja fidelidad probablemente sería fijar una UIViewque es la altura de la barra de navegación en la parte superior de la vista detrás de la barra. Haga que la vista sea del 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

ingrese la descripción de la imagen aquí

(Se cambió el color de los ejemplos inferiores a énfasis en la transparencia. La transparencia / desenfoque es más notable cuando está en movimiento).

Subclasificar UINavigationBary colocar esa misma vista sobre el fondo, pero detrás de todo lo demás, probablemente obtendrá resultados similares a la vez que será menos hacky.


Otra solución que he visto es jugar con el alfa del UINavigationBar:

self.navigationController.navigationBar.alpha = 0.5f;

Editar: en realidad, después de probar, parece que esto no proporciona el comportamiento previsto (o cualquier comportamiento):

.8 alfa

Barra de navegación con .8 alfa

Alfa no ajustado

ingrese la descripción de la imagen aquí

Obviamente, solo querrás hacer esto en dispositivos iOS 7. Por lo tanto, agregue alguna verificación de versión antes de implementar cualquiera de estos.


Segundo el enfoque de actualizar el alfa y el tintColor para obtener el color que estás buscando.
StuartM

Si puede obtener los efectos deseados con esa forma menos invasiva, entonces totalmente. Pero no estoy seguro de cuán efectivo será.
Kevin

El único problema que tengo con esto (y no parece representado en su imagen) es que está agregando la vista directamente en la parte superior de la barra de navegación, y como resultado, está bloqueando los controles: cl.ly / image / 3d3C2o0N283S
SpacePyro

Vaya, ahora veo. Debería ser[self.navigationController.view insertSubview:backgroundView belowSubview:self.navigationController.navigationBar];
Kevin

Sí, supuse que a eso te referías. ;) Esto definitivamente me da una mejor gama de colores para elegir. Probablemente sea imposible obtener la vitalidad del color original teniendo en cuenta que el efecto de desenfoque todavía desatura realmente cualquier cosa debajo de él. Solo tendré que vivir con un color más oscuro por ahora.
SpacePyro

4

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 que describe este método aquí )

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 ( Enlace GitHub ) de David Keegan para modificar los colores existentes.


3

Apple ha solucionado el problema en la nueva versión 7.0.3.


1
Sí, su implementación de color de tinte definitivamente ha cambiado en 7.0.3. Ahora puedo lograr mi color deseado simplemente aumentando la saturación en aproximadamente un 10-15%. Antes también necesitaba agregar la capa extra.
Matej Bukovinski

¡Gracias por hacérmelo saber! Enviaré una actualización a mi biblioteca para esto.
SpacePyro

1
Y sin fijar en 7.1> _ <
Leo Natan

1

Solía @ solución de aprato pero encontrado algunos casos de esquina donde las nuevas capas de nuevos VCs (por ejemplo. UINavigationItemButtonViews, UINavigationItemViews, Etc) se inserta automáticamente en una posición por debajo de la extraColorLayer(que haría que esos elementos del título botón o para ser afectados por la extraColorLayery por lo tanto más tenue en color de lo que normalmente serían). Así que ajusté la solución de @ aprato para forzar extraColorLayerque permanezca en la posición de índice 1. En la posición de índice 1, la extraColorLayerqueda justo por encima de_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
}

Dado que las capas y las subvistas no se mezclan, creo que la sobrecarga de addSubView no es necesaria
Rob van der Veer


0

Ninguno de estos hacks es obligatorio :). Simplemente configure:

self.navigationController.navigationBar.translucent = NO;

Para iOS 7, la translucidez predeterminada se ha mantenido en VERDADERO.


17
Pero la pregunta también requiere translucidez.
Leo Natan

:) Gracias, funcionó para mí. Sin embargo, hay un borde inferior negro de 1 px debajo de la barra de navegación. ¿Hay alguna forma de eliminarlo?
Pritesh Desai

0

En una nota relacionada, puede configurar 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];

1
Si está tratando de hacer coincidir el estilo de iOS 7, probablemente sea inapropiado usar una sombra paralela en el texto del título.
Nick Locking

Tienes razón, en iOS 7 Apple ya no está configurando sombras en el texto de su barra de navegación. Sin embargo, si desea una apariencia personalizada, esto le daría la opción.
bryguy1300

0

Me encontré con este Q / A al intentar configurar una barra de navegación de color uniforme con transparencia DESACTIVADA en iOS 7.

Después de experimentar un tiempo con barTintColor, descubrí que una manera muy fácil de tener una barra de navegación opaca es hacer una imagen de un solo píxel del color deseado, hacer una imagen estirable y ponerla 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 AMBOS en iOS 6 e iOS 7 (barTintColor no es compatible con iOS 6).


0

Hay un gran reemplazo de Dropin UINavigationController disponible de Simon Booth disponible en GitHub Here GitHub - C360NavigationBar

Si es compatible con iOS6 hacia atrás, verifique el controlador de 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;

A menos que me falte algo, las barras de esta biblioteca no son translúcidas.
Rivera

0

Como @bernhard mencionó 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 de tinte de la barra translúcida para que el color real de la barra coincida con el color deseado en iOS 7.xy versiones posteriores. Mira esta respuesta para más detalles.


-1

Hablando francamente, las respuestas anteriores pueden ser correctas, pero el siguiente 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.imageRedy self.imageBlack.

< self.imageBlack> la imagen en negro está entre paréntesis no será visible ya que es transparente :)

< self.imageRed> la imagen roja está entre paréntesis.


Esto no te da desenfoque.
Ortwin Gentz

-1

¿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 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


¿No podrías envolver tu UIViewControllerinterior UINavigationControllercon [[[UINavigationController alloc] initWithRootViewController:<YourViewController>]? Esto también puede responderse mejor como una pregunta separada, en lugar de publicar aquí.
SpacePyro

-2

Una manera fácil de obtener el color que desea es usar

    [<NAVIGATION_BAR> setBackgroundImage:<UIIMAGE> forBarPosition:<UIBARPOSITION> barMetrics:<UIBARMETRICS>];

Mientras su imagen tenga algo de alfa, la translucidez funcionará y puede establecer el alfa cambiando la imagen. Esto se acaba de agregar en iOS7. El ancho y el alto de la imagen son 640x88px para vertical (agregue 20 a 88 si desea que esté debajo de la barra de estado).


Sin embargo, esto no retiene el desenfoque. Hay transparencia, pero no hay desenfoque.
Leo Natan
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.