Conseguir cores vivas e brilhantes para um UINavigationBar translúcido do iOS 7


172

ATUALIZAÇÃO DO iOS 7.1 : Parece que a solução alternativa para modificar o canal alfa na UINavigationBar foi ignorada nesta atualização. No momento, a melhor solução parece ser apenas "lidar com isso" e esperar que qualquer cor escolhida possa gerar um efeito translúcido. Ainda estou procurando maneiras de contornar isso.


ATUALIZAÇÃO DO iOS 7.0.3 : A biblioteca do GitHub que criamos foi atualizada para solucionar um pouco esse problema ao usar o iOS 7.0.3. Infelizmente, não existe uma fórmula mágica para suportar as duas cores criadas no iOS 7.0.2 e anterior e iOS 7.0.3. Parece que a Apple melhorou a saturação, mas à custa da opacidade (já que a translucidez borrada depende do nível de opacidade). Eu, juntamente com alguns outros, estamos trabalhando para criar uma correção muito melhor para isso.


Tenho certeza que muitas pessoas já se depararam com o problema em que o iOS 7 tende a dessaturar a cor de uma UINavigationBar que é translúcida.

Meu objetivo é conseguir um UINavigationBar com essa cor de tonalidade, mas translúcido:

UINavigationBar, Opaco

No entanto, com translucidez, estou entendendo isso. A vista de fundo é branca, o que eu entendo tornará essa vista um pouco mais clara:

UINavigationBar, Translúcido

Existe alguma maneira de obter a cor original enquanto ainda possui translucidez? Percebi que o Facebook conseguiu que a barra tivesse sua cor azul rica, como mostrado aqui:

Facebook UINavigationBar, Translúcido

.. então eu sei que tem que haver alguma maneira. As visualizações de plano de fundo obviamente fazem a diferença aqui, mas a maior parte do conteúdo também é cinza / branco. Parece que, independentemente da cor da tonalidade da barra, você é incapaz de obter cores vivas sob a translucidez.

Atualizado com solução.

Aqui está a solução que acabei encontrando. Tomei aprato solução 's e depois abrangeu o costume UINavigationBardentro de uma UINavigationControllersubclasse. Eu criei um repositório que tem essa implementação listada abaixo, juntamente com um aplicativo de exemplo .

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

o Facebook iOS7 não é UINAvigationBaropaco?
Vinzzz

Não, é uma transparência muito mais sutil que o iOS padrão. Muito melhor, IMO.
21413 Kevin

A barra de navegação não é transparente
LE SANG

7
É definitivamente translúcido; por favor, veja minha resposta editada.
SpacePyro

2
@Odelya - Esta não é uma solução para obter as cores corretas, mas sim uma solução para corrigir a claridade da UINavigationBarmelhor forma possível quando expostos a translucidez iOS 7.
SpacePyro

Respostas:


52

Atualização do iOS 7.0.3: Como você vê acima, o 7.0.3 mudou as coisas. Eu atualizei minha essência. Espero que isso acabe quando as pessoas atualizarem.

Resposta original: Acabei com um hack combinando as duas das outras respostas. Estou subclassificando UINavigationBar e adicionando uma camada à parte traseira com algum espaço extra para cobrir se alguma das várias barras de status de altura estiver ativa. A camada é ajustada nas subvisões de layout e a cor muda sempre que você define 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);
  }

Onde você implementou isso no ViewController? Sob viewDidLoad?
21413 Jeremy

Isso funciona lindamente! Decidi adicionar isso à minha UINavigationControllersubclasse. Aqui está uma essência para aqueles que estão interessados ​​em ter um costume UINavigationBardentro de um UINavigationController.
SpacePyro 23/09

@ Jeremy como SpacePyro Eu tenho uma subclasse de controlador de navegação (que, como a barra que eu estava usando antes do 7 para o direcionamento de aparência UIApp), que substitui o initWithRootViewControlleruso. Eu atualizei a minha essência
Anthony

Hum ... ok .. Acho que preciso ver isso em um projeto de teste inteiro para entender completamente o que você quer dizer. Consegui replicar o exemplo do timeuser abaixo, mas ainda estou um pouco verde com este.
Jeremy

1
@ Mr.T Obrigado! Quando eu escrevi, não foi empurrando ainda :) Mas eu tenho atualizado agora, acrescentou UIAppearance para a opacidade e suporte para NSCoding
Anthony

10

O comportamento do tintColor for bars mudou no iOS 7.0. Ele não afeta mais o fundo da barra e se comporta como descrito para a propriedade tintColor adicionada ao UIView. Para colorir o fundo da barra, use -barTintColor. Você pode usar o código a seguir para fazer o aplicativo funcionar com o ios6 e o ​​ios7.

if(IS_IOS7)
{
    self.navigationController.navigationBar.barTintColor = [UIColor blackColor];
    self.navigationController.navigationBar.translucent = NO;
}
else
{
    self.navigationController.navigationBar.tintColor = [UIColor blackColor];
}

IS_IOS7 é uma macro que é definida no arquivo pch da seguinte maneira.

#define IS_IOS7 ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0)

9

Não encontrei esta solução, mas parece funcionar bastante bem. Acabei de adicioná-lo ao viewDidLoad na minha subclasse de UINavigationController.

Fonte: 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, depois de empurrar um novo View Controller para o Navigation, qualquer item do botão de barra é movido para ficar sob essa camada de transparência.
Evan Davis

Os títulos também ficam obscurecidos por essa camada de transparência.
Nick Locking

Eu escrevi essa essência. Os comentários estão certos; os itens de botão são pressionados por baixo quando um novo controlador de exibição é pressionado ou as subcamadas estão herdando o alfa de colourView. I bifurcada a outra resposta e fixa algumas coisas em um novo drop-in class: github.com/alanzeino/AZColoredNavigationBar
Alan Zeino

Consegui colocar o texto em branco selecionando o estilo da barra de navegação em preto translúcido ... isso fez o truque para mim. Defina também yourBar.tintColor = [UIColor whiteColor]; para outros botões personalizados na parte superior.
Juan Zamora

6

Uma maneira de baixa fidelidade provavelmente seria fixar uma UIViewque seja a altura da barra de navegação na parte superior da vista atrás da barra. Faça com que essa visualização tenha a mesma cor da barra de navegação, mas brinque com o alfa até obter os efeitos desejados:

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];

Veja atrás

insira a descrição da imagem aqui

(Cor alterada dos exemplos mais baixos para enfatizar a transparência. Transparência / desfoque é mais perceptível quando em movimento.)

Subclassificar UINavigationBare colocar a mesma exibição acima do plano de fundo, mas por trás de todo o resto, provavelmente obterá resultados semelhantes, sendo menos invasivo.


Outra solução que eu já vi é brincar com o alfa do UINavigationBar:

self.navigationController.navigationBar.alpha = 0.5f;

Edit: Na verdade, após o teste, parece que isso não fornece o comportamento pretendido (ou qualquer comportamento):

.8 alfa

Barra de navegação com 0,8 alfa

Alfa não ajustado

insira a descrição da imagem aqui

Obviamente, você só desejará fazer isso em dispositivos iOS 7. Portanto, adicione alguma verificação de versão antes de implementar qualquer uma delas.


Segundo a abordagem de atualizar o alfa e o tintColor para obter a cor que você está procurando.
StuartM

Se você pode obter os efeitos desejados dessa maneira menos invasiva, totalmente. Mas não tenho certeza de quão eficaz será.
21413 Kevin

O único problema que estou enfrentando com isso (e não parece representado na sua foto) é que ele está adicionando a visualização diretamente em cima da barra de navegação e, como resultado, está causando o bloqueio dos controles: cl.ly / image / 3d3C2o0N283S
SpacePyro 19/09/2013

Opa, agora eu vejo. Deve ser[self.navigationController.view insertSubview:backgroundView belowSubview:self.navigationController.navigationBar];
Kevin

Sim, achei que era isso que você queria dizer. ;) Definitivamente, isso me dá uma gama melhor de cores para escolher. Obter a vibração da cor original provavelmente será impossível, considerando que o efeito de desfoque ainda dessatura realmente qualquer coisa sob ela. Só vou ter que viver com uma cor mais escura por enquanto.
SpacePyro 19/09/2013

4

Em vez de criar seu objeto UIColor no formato RGB , use HSB e aumente o parâmetro de saturação. (Créditos a Sam Soffes, que descreve este método aqui )

navigationBar.barTintColor = [UIColor colorWithHue:0.555f saturation:1.f brightness:0.855f alpha:1.f];

Nota: Esta solução é uma troca e não funciona bem para cores com alta saturação.

Para escolher a cor HSB do seu design, você pode usar uma ferramenta como o ColorSnapper, que permite copiar o formato UIColor HSB.

Você também pode tentar a Categoria UIColor ( Link do GitHub ) de David Keegan para modificar as cores existentes.


3

O problema foi corrigido pela Apple na nova versão 7.0.3.


1
Sim, a implementação da cor da tonalidade mudou definitivamente na 7.0.3. Agora posso alcançar a cor desejada apenas aumentando a saturação em cerca de 10 a 15%. Antes, eu também precisava adicionar uma camada extra.
Matej Bukovinski

Obrigado por me avisar! Vou enviar uma atualização para minha biblioteca para isso.
SpacePyro 23/10

1
E não corrigido em 7.1> _ <
Leo Natan 27/03

1

I utilizado @ solução de aprato mas encontrados alguns casos de canto onde as novas camadas de novos VCs (por ex. UINavigationItemButtonViews, UINavigationItemViews, Etc.) iria ser inseridos automaticamente para uma posição abaixo da extraColorLayer(o que causaria essas título ou botão elementos de ser afectada pelo extraColorLayere assim cores mais fracas do que normalmente seriam). Então ajustei a solução da @ aprato para forçar a extraColorLayerpermanecer na posição de índice 1. Na posição de índice 1, a posição extraColorLayerfica acima da _UINavigationBarBackground, mas abaixo de todo o resto.

Aqui está a minha implementação de classe:

- (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
}

Desde camadas e subviews não são misturados, coisa que eu sobrecarregar addSubview não é necessário
Rob van der Veer


0

Nenhum desses hacks é necessário :). Basta definir:

self.navigationController.navigationBar.translucent = NO;

Para o iOS 7, a translucidez padrão foi mantida em TRUE.


17
Mas a questão também requer translucidez.
quer

:) Obrigado, funcionou para mim. No entanto, há uma borda inferior preta de 1px sob a barra de navegação. Existe alguma maneira de removê-lo?
Pritesh Desai

0

Em uma nota relacionada, você pode definir facilmente a cor do texto do título (com sombra) atravé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
Se você está tentando combinar com o estilo do iOS 7, é provável que usar uma sombra no texto do título seja inapropriado.
Nick Locking

Você está correto, no iOS 7, a Apple não está mais definindo sombras no texto da barra de navegação. Se você quisesse uma aparência personalizada, isso lhe daria a opção.
precisa saber é o seguinte

0

Encontrei este Q / A ao tentar configurar uma barra de navegação uniformemente colorida com transparência DESATIVADA no iOS 7.

Depois de experimentar um pouco o barTintColor, descobri que uma maneira muito fácil de ter uma barra de navegação opaca é criar uma imagem de pixel único da cor desejada, criar uma imagem elástica e defini-la como plano de fundo. .

UIImage *singlePixelImage = [UIImage imageNamed:@"singlePixel.png"];
UIImage *resizableImage = [singlePixelImage resizableImageWithCapInsets:UIEdgeInsetsZero];
[navigationBar setBackgroundImage:resizableImage forBarMetrics:UIBarMetricsDefault]; 

Três linhas de código, muito simples e funcionam AMBOS no iOS 6 e iOS 7 (barTintColor não é suportado no iOS 6).


0

Existe uma excelente substituição do Dropin UINavigationController disponível a partir de Simon Booth, disponível no GitHub Here GitHub - C360NavigationBar

Se você estiver com suporte ao iOS6 para trás, verifique o controlador de exibição raiz como:

PatientListTableViewController * frontViewController = [[PatientListTableViewController alocado] 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 esteja faltando alguma coisa, as barras desta biblioteca não são translúcidas.
Rivera

0

Como o @bernhard mencionado acima , é possível saturar a cor da barra para obter a aparência desejada da barra de navegação.

Eu escrevi um utilitário BarTintColorOptimizer para esse tipo de ajuste. Ele otimiza a cor translúcida da tonalidade da barra para fazer com que a cor real da barra corresponda à cor desejada no iOS 7.xe posterior. Veja esta resposta para obter detalhes.


-1

Francamente falando, as respostas acima podem estar certas, mas seguir o truque funcionou para mim com muita facilidade.

// 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];

Aqui estão as imagens usadas para self.imageRede self.imageBlack.

< self.imageBlack> a imagem preta está entre parênteses, não será visível, pois é transparente :)

< self.imageRed> imagem vermelha está entre parênteses.


Isso não deixa você borrado.
Ortwin Gentz

-1

existe uma maneira de usar a solução @aprato sem subclassificar UINavigationBar.

No meu projeto, minha visão principal é um UIViewController.

o problema é que o navigationController é uma propriedade somente leitura, existe uma maneira de usar sua classe com meu projeto porque eu não posso usar: [[UINavigationController alloc] initWithNavigationBarClass:

obrigado


Você não poderia simplesmente envolver seu UIViewControllerinterior UINavigationControllercom um [[[UINavigationController alloc] initWithRootViewController:<YourViewController>]? Isso também pode ser melhor respondido como uma pergunta separada, em vez de postar aqui.
SpacePyro

-2

Uma maneira fácil de obter a cor desejada é usando

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

Contanto que sua imagem tenha algum alfa, a translucidez funcionará e você poderá defini-lo alterando a imagem. Isso foi adicionado no iOS7. A largura e a altura da imagem são 640x88px na vertical (adicione 20 aos 88 se desejar que ela fique embaixo da barra de status).


No entanto, isso não retém o desfoque. Há transparência, mas não há desfoque.
Leo Natan
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.