it-swarm.com.ru

Достижение ярких, ярких цветов для полупрозрачного UINavigationBar для iOS 7


ОБНОВЛЕНИЕ iOS 7.1 : похоже, что обходной путь для изменения альфа-канала в UINavigationBar был проигнорирован в этом обновлении. В данный момент лучшим решением, кажется, является "справиться с этим" и надеяться, что любой выбранный вами цвет может оказать полупрозрачный эффект. Я все еще ищу способы обойти это.


ОБНОВЛЕНИЕ iOS 7.0.3 : созданная нами библиотека GitHub была обновлена, чтобы немного обойти эту проблему при использовании iOS 7.0. 3. К сожалению, нет волшебной формулы для поддержки обоих цветов, созданных в iOS 7.0.2 и более ранних версиях и iOS 7.0.3. Похоже, Apple улучшил насыщенность, но за счет непрозрачности (поскольку размытая прозрачность зависит от уровня непрозрачности). Я, вместе с несколькими другими, работаю над созданием гораздо лучшего решения для этого.


Я уверен, что многие люди уже сталкивались с проблемой, когда iOS 7 имеет тенденцию к снижению цвета полупрозрачного UINavigationBar.

Моя цель - создать UINavigationBar с этим оттенком, но прозрачным:

UINavigationBar, Opaque

Однако, с полупрозрачностью, я получаю это. Фоновый вид белого цвета, что, как я понимаю, сделает этот вид немного светлее:

UINavigationBar, Translucent

Есть ли способ достичь оригинального цвета, сохраняя прозрачность? Я заметил, что Facebook удалось сделать их бар насыщенным синим цветом, как показано здесь:

Facebook UINavigationBar, Translucent

... так что я знаю, что должен быть какой-то путь. Фоновые представления, очевидно, имеют значение здесь, но большая часть их содержимого также серого/белого цвета. Кажется, что независимо от того, какой цвет оттенка вы используете, вы не сможете получить яркие цвета при прозрачности.

Обновлено с решением.

Вот решение, которое я в итоге придумал. Я принял решение aprato , а затем включил пользовательское UINavigationBar в подкласс UINavigationController. Я создал репозиторий, в котором эта реализация указана ниже, вместе с примером приложения .

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

ОБНОВЛЕНИЕ iOS 7.0.3: Как вы видели выше, 7.0.3 изменил ситуацию. Я обновил свой Gist. Надеюсь, это просто исчезнет, ​​когда люди обновятся.

Оригинальный ответ: Я получил хак, сочетающий два других ответа. Я создаю подкласс UINavigationBar и добавляю слой на заднюю часть с дополнительным пространством для покрытия, если какая-либо из различных строк состояния высоты вверх. Слой корректируется в подпредставлениях макета, и цвет меняется каждый раз, когда вы устанавливаете barTintColor.

Суть: 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

Поведение tintColor для баров изменилось на iOS 7.0. Он больше не влияет на фон панели и ведет себя так, как описано для свойства tintColor, добавленного в UIView. Чтобы тонировать фон панели, используйте -barTintColor. Вы можете использовать следующий код, чтобы приложение работало как с ios6, так и с ios7.

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

IS_IOS7 - это макрос, который определяется в файле pch следующим образом.

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

Я не придумал это решение, но, похоже, оно работает довольно хорошо. Я только добавил это к viewDidLoad на моем подклассе UINavigationController.

Источник: 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

Вероятно, одним из способов низкого уровня будет закрепление UIView, то есть высоты панели навигации, в верхней части представления за панелью. Сделайте этот вид того же цвета, что и панель навигации, но играйте с альфа-каналом, пока не получите желаемый эффект:

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 позади

enter image description here

(Изменен цвет с более низких примеров на прозрачность выделения. Прозрачность/размытие более заметны при движении.)

Создание подкласса UINavigationBar и размещение того же представления над фоном, но за всем остальным, вероятно, приведет к аналогичным результатам, но при этом будет менее хакерским.


Другое решение, которое я видел, это игра с альфа-версией UINavigationBar:

self.navigationController.navigationBar.alpha = 0.5f;

Правка: На самом деле, после тестирования кажется, что это не обеспечивает поведение намерения (или любое поведение):

.8 альфа

Navigation bar with .8 alpha

Нескорректированная альфа

enter image description here

Очевидно, вы захотите делать это только на устройствах iOS 7. Итак, добавьте некоторую проверку версии , прежде чем реализовывать какой-либо из них.

6
Kevin

Вместо создания объекта UIColor в формате RGB используйте HSB и увеличьте параметр насыщенности. (Авторы Сэм Соффс кто описывает этот метод здесь )

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

Примечание. Это решение является компромиссным и не подходит для цветов с высокой насыщенностью.

Чтобы выбрать цвет HSB из вашего дизайна, вы можете использовать инструмент наподобие ColorSnapper , который позволяет вам просто скопировать формат HSB UIColor.

Вы также можете попробовать UIColor Category ( GitHub Link ) из David Keegan , чтобы изменить существующие цвета.

4
bernhard

Теперь проблема исправлена ​​Apple в новом выпуске 7.0.3.

3
smad

Я улучшил ваш код в моем форке: https://github.com/allenhsu/CRNavigationController

С моей модификацией результирующий цвет на экране (выбранный на белом фоне) будет точно таким же значением, переданным в setBarTintColor. Я думаю, что это удивительное решение.

1
Allen Hsu

Я использовал решение @ aprato, но обнаружил несколько угловых случаев, когда новые слои из новых VC (например, UINavigationItemButtonViews, UINavigationItemViews и т.д.) Будут автоматически вставлены в позицию ниже extraColorLayer (что приведет к тому, что на элементы title или button будут влиять extraColorLayer и, следовательно, более тусклый, чем обычно). Поэтому я настроил решение @ aprato, чтобы extraColorLayer оставался в позиции индекса 1. В позиции индекса 1 extraColorLayer остается прямо над _UINavigationBarBackground, но под всем остальным.

Вот моя реализация класса:

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

Ни один из этих хаков не требуется :). Просто установите:

self.navigationController.navigationBar.translucent = NO;

Для iOS 7 прозрачность по умолчанию была сохранена в TRUE.

0
rishabh

Я сталкивался с этим вопросом, пытаясь настроить однородно окрашенную панель навигации с отключенной прозрачностью на iOS 7.

Поэкспериментировав некоторое время с barTintColor, я понял, что очень простой способ создания непрозрачной навигационной панели - создать однопиксельное изображение нужного цвета, сделать растягиваемое изображение из него и установить его в backgroundImage навигационной панели. ,.

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

Три строки кода, очень простые и работающие ОБА на iOS 6 и iOS 7 (barTintColor не поддерживается на iOS 6).

0
bizz84

Вот отличная замена Dropin UINavigationController, доступная от Саймона Бута, доступная на GitHub Here GitHub - C360NavigationBar

Если вы поддерживаете iOS6 в обратном направлении, сделайте проверку корневого контроллера вида следующим образом:

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

В связанной заметке вы можете легко установить цвет текста заголовка (с тенью) с помощью:

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

Как @bernhard упомянуто выше возможно насыщать цветовой оттенок полосы, чтобы получить желаемый внешний вид навигационной панели.

Я написал утилита BarTintColorOptimizer для такого рода настройки. Он оптимизирует цвет оттенка полупрозрачной полосы, чтобы фактический цвет полосы соответствовал желаемому цвету в iOS 7.x и более поздних версиях. Посмотрите этот ответ для деталей.

0
IvanRublev