web-dev-qa-db-fra.com

Obtention de couleurs vives et éclatantes pour une barre UINavigationBar translucide iOS 7


iOS 7.1 UPDATE : la solution de contournement permettant de modifier le canal alpha dans la barre UINavigationBar a été ignorée dans cette mise à jour. À l'heure actuelle, la meilleure solution semble être de simplement "s'en occuper" et d'espérer que la couleur choisie rende un effet translucide. Je cherche toujours des moyens de contourner ce problème.


MISE À JOUR iOS 7.0.3 : La la bibliothèque GitHub que nous avons créée a été mise à jour pour contourner légèrement ce problème lorsque vous utilisez iOS 7.0. 3 Malheureusement, aucune formule magique ne prend en charge les couleurs créées dans iOS 7.0.2 et versions antérieures et iOS 7.0.3. On dirait que Apple a amélioré la saturation, mais au détriment de l’opacité (la translucidité floue dépend du niveau d’opacité). Je travaille avec quelques autres pour créer une bien meilleure réparer pour cela.


Je suis sûr que de nombreuses personnes ont déjà rencontré le problème suivant: iOS 7 a tendance à désaturer la couleur d'un UINavigationBar translucide.

Mon objectif est de réaliser un UINavigationBar avec cette teinte, mais translucide:

UINavigationBar, Opaque

Cependant, avec la transparence, je comprends cela. La vue d’arrière-plan est blanche, ce qui, je pense, la rendra un peu plus claire:

UINavigationBar, Translucent

Est-il possible d'obtenir la couleur d'origine tout en conservant la transparence? J'ai remarqué que Facebook avait réussi à obtenir que leur barre soit de leur couleur bleu riche, comme indiqué ici:

Facebook UINavigationBar, Translucent

..so je sais qu'il doit y avoir un moyen. Les images d'arrière-plan font évidemment une différence, mais la plupart de leur contenu est également gris/blanc. Il semble que, quelle que soit la couleur de la teinte que vous avez insérée, vous ne parvenez pas à obtenir des couleurs vives avec une transparence.

Mise à jour avec la solution.

Voici la solution que j'ai finalement trouvée. J'ai pris la solution de aprato , puis j'ai intégré la coutume UINavigationBar dans une sous-classe UINavigationController. J'ai créé un référentiel dont l'implémentation est répertoriée ci-dessous, avec un exemple d'application .

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

MISE À JOUR iOS 7.0.3: Comme vous le voyez ci-dessus, la version 7.0.3 a changé les choses. J'ai mis à jour mon Gist. Espérons que cela va simplement disparaître à mesure que les gens évoluent.

Réponse originale: Je me suis retrouvé avec un bidouillage combinant les deux autres réponses. Je sous-classe UINavigationBar et j'ajoute une couche à l'arrière avec un espace supplémentaire à couvrir si l'une des différentes barres d'état de hauteur est levée. Le calque est ajusté dans les vues secondaires de la disposition et la couleur change chaque fois que vous définissez barTintColor.

Gist: https://Gist.github.com/aprato/663139

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);
  }
52
Anthony

Le comportement de tintColor pour les barres a changé sur iOS 7.0. Il n'affecte plus l'arrière-plan de la barre et se comporte comme décrit pour la propriété tintColor ajoutée à UIView. Pour colorer l'arrière-plan de la barre, utilisez -barTintColor.Vous pouvez utiliser le code suivant pour que l'application fonctionne avec ios6 et ios7.

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

IS_IOS7 est une macro qui est définie dans le fichier pch comme suit.

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

Je n'ai pas trouvé cette solution, mais elle semble fonctionner assez bien. Je viens de l'ajouter à viewDidLoad sur ma sous-classe de UINavigationController.

Source: https://Gist.github.com/alanzeino/661925

// 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];
9
Jamie Hamick

Un moyen peu fiable serait probablement d'épingler un UIView correspondant à la hauteur de la barre de navigation située en haut de la vue située derrière la barre. Faites en sorte que la vue ait la même couleur que la barre de navigation, mais jouez avec l'alpha jusqu'à ce que vous obteniez les effets souhaités:

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 derrière

enter image description here

(Couleur modifiée des exemples inférieurs en accentuation de la transparence. La transparence/le flou est plus visible en mouvement.)

Sous-classer le UINavigationBar et placer cette même vue au-dessus de l'arrière-plan mais derrière tout le reste, vous obtiendrez probablement des résultats similaires tout en étant moins piraté.


Une autre solution que j'ai vue bouleversée est de jouer avec l'alpha du UINavigationBar:

self.navigationController.navigationBar.alpha = 0.5f;

Edit: En fait, après les tests, il semble que cela ne fournisse pas le comportement souhaité (ni aucun comportement):

.8 alpha

Navigation bar with .8 alpha

Alpha non ajusté

enter image description here

Évidemment, vous ne voudrez le faire que sur des appareils iOS 7. Donc, ajoutez une vérification de version avant d’implémenter l’une d’elles.

6
Kevin

Au lieu de créer votre objet UIColor au format RGB , utilisez HSB et augmentez le paramètre de saturation. (Crédits à Sam Soffes qui décrit cette méthode ici )

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

Remarque: cette solution est un compromis et ne fonctionne pas bien pour les couleurs à saturation élevée.

Pour choisir la couleur HSB de votre conception, vous pouvez utiliser un outil tel que ColorSnapper qui vous permet de copier simplement le format UIColor HSB.

Vous pouvez également essayer la catégorie UIColor ( GitHub Link ) de David Keegan pour modifier les couleurs existantes.

4
bernhard

Le problème a maintenant été résolu par Apple dans la nouvelle version 7.0.3.

3
smad

J'ai amélioré votre code dans ma fourchette: https://github.com/allenhsu/CRNavigationController

Avec ma modification, la couleur de résultat à l'écran (sélectionnée sur un fond blanc) correspondra exactement à la même valeur transmise à setBarTintColor. Je pense que c'est une solution incroyable.

1
Allen Hsu

J'ai utilisé la solution de @ aprato, mais j'ai trouvé quelques cas où les nouvelles couches de nouveaux VC (par exemple, UINavigationItemButtonViews, UINavigationItemViews, etc.) seraient automatiquement insérées dans une position inférieure à la extraColorLayer (qui aurait pour effet que les éléments de titre ou de bouton soient affectés par le extraColorLayer et par conséquent plus pâles qu’ils le seraient normalement). J'ai donc ajusté la solution de @ aprato pour forcer le extraColorLayer à rester à la position d'index 1. À la position d'index 1, le extraColorLayer reste juste au-dessus du _UINavigationBarBackground, mais sous tout le reste.

Voici ma mise en œuvre 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
}
1
Mr. T

Aucune de ces hacks n'est requise :). Simplement définir:

self.navigationController.navigationBar.translucent = NO;

Pour iOS 7, la translucidité par défaut a été maintenue sur TRUE.

0
rishabh

Je suis tombé sur cette Q/A en essayant de configurer une barre de navigation de couleur uniforme avec la transparence DÉSACTIVÉE sur iOS 7.

Après avoir expérimenté quelque temps avec barTintColor, j’ai compris qu’un moyen très simple d’avoir une barre de navigation opaque consiste à créer une image unique en pixels de la couleur désirée, à en faire une image extensible et à la placer à l’arrière-planImage de la barre de navigation .

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

Trois lignes de code, très simples et fonctionnant à la fois sur iOS 6 et iOS 7 (barTintColor n'est pas pris en charge sur iOS 6).

0
bizz84

Il existe un excellent remplacement Dropin UINavigationController disponible auprès de Simon Booth disponible sur GitHub Ici GitHub - C360NavigationBar

Si vous prenez en charge iOS6 en arrière, effectuez une vérification du contrôleur de vue racine en tant que telle:

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;
0
DoctorG

Sur une note connexe, vous pouvez définir facilement la couleur du texte de votre titre (avec ombre) via:

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

Comme @bernhard mentionné ci-dessus , il est possible de saturer la couleur de la teinte de la barre pour obtenir l'apparence souhaitée de la barre de navigation.

J'ai écrit un tilitaire BarTintColorOptimizer pour ce type d'ajustement. Il optimise la couleur de teinte de la barre translucide pour que la couleur réelle de la barre corresponde à la couleur souhaitée dans iOS 7.x et versions ultérieures. Regardez cette réponse pour plus de détails.

0
IvanRublev