Досягнення яскравих, яскравих кольорів для iOS 7 напівпрозорого UINavigationBar


172

Оновлення 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, напівпрозорий

Чи є спосіб досягти оригінального кольору, зберігаючи напівпрозорість? Я помітив, що 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

Хіба Facebook iOS7 UINAvigationBarнепрозорий?
Вінцз

Ні, це набагато більш тонка прозорість, ніж iOS за замовчуванням. Набагато краще, ІМО.
Кевін

Facebook NavigationBar не прозорий
LE SANG

7
Це однозначно напівпрозоре; будь ласка, дивіться мою відредаговану відповідь.
SpacePyro

2
@Odelya - Це не рішення для отримання правильних кольорів, а скоріше рішення для виправлення максимально легкої легкості під UINavigationBarчас впливу напівпрозорості в iOS 7.
SpacePyro

Відповіді:


52

Оновлення iOS 7.0.3: Як ви бачите вище, 7.0.3 змінив речі. Я оновив свою суть. Сподіваємось, це просто піде в міру оновлення людей.

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

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

Де ви реалізували це на ViewController? Під viewDidLoad?
Джеремі

Це прекрасно працює! Я вирішив додати це до свого UINavigationControllerпідкласу. Ось суть його для тих, хто зацікавлений у користуванні користувачем UINavigationBarу межах UINavigationController.
SpacePyro

@Jeremy, як SpacePyro У мене є підклас контролера nav (який як бар, який я використовував до 7 для націлювання на UIAppearance), який переосмислює initWithRootViewControllerйого використання. Я оновив свою суть
Ентоні

Гм ... гаразд ... Я думаю, мені потрібно бачити це в цілому тестовому проекті, щоб повністю зрозуміти, що ти маєш на увазі. Я зміг повторити приклад timeuser нижче, але я ще трохи зелений з цим.
Джеремі

1
@ Mr.T Дякую! Коли я написав, це ще не наштовхується :) Але я оновив його зараз, додав появу UIA для непрозорості та підтримки NSCoding
Ентоні,

10

Поведінка 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)

9

Я не придумав це рішення, але, здається, він працює досить добре. Я щойно додав його до viewDidLoad на своєму підкласі UINavigationController.

Джерело: 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
Схоже, що після натискання нового контролера перегляду на регулятор навігації, будь-які елементи панелі кнопок переміщуються, щоб вони знаходилися під цим шаром прозорості.
Еван Девіс

Заголовки також затьмарюються цим шаром прозорості.
Блокування Ніка

Я написав цю суть. Коментарі правильні; або кнопкові елементи підсуваються внизу, коли натискається новий контролер перегляду або підшари успадковують альфа colourView. Я відповів на іншу відповідь і зафіксував декілька речей у новому класі: github.com/alanzeino/AZColoredNavigationBar
Alan Zeino

Мені вдалося помістити текст у білий колір, вибравши стиль «Прозорий чорний навігаційний рядок» ... це зробило для мене трюк. Також встановіть yourBar.tintColor = [UIColor whiteColor]; для інших спеціальних кнопок у верхній частині
Хуан Замора

6

Одним із способів із низьким рівнем фіксації, ймовірно, було б прикріплення а 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 позаду

введіть тут опис зображення

(Змінено колір від нижчих прикладів до прозорості акценту. Прозорість / розмитість помітніша під час руху.)

Підкласифікація UINavigationBarта розміщення цього самого виду над фоном, але позаду всього іншого, ймовірно, досягнуть подібних результатів, не будучи менш хакітними.


Ще одне рішення, яке я бачив, кинувшись навколо, - це грати з альфами UINavigationBar:

self.navigationController.navigationBar.alpha = 0.5f;

Редагувати: насправді після тестування здається, що це не забезпечує намічену поведінку (або будь-яку поведінку):

.8 альфа

Панель навігації з .8 альфа

Непристосований альфа

введіть тут опис зображення

Очевидно, ви захочете це зробити лише на пристроях iOS 7. Отже, додайте перевірку версій, перш ніж здійснити будь-яку з них.


Я другий підхід до оновлення альфа та tintColor, щоб отримати потрібний вам колір.
StuartM

Якщо ви можете отримати бажані ефекти тим менш інвазивним способом, то повністю. Але я не впевнений, наскільки це буде ефективно.
Кевін

Єдине питання, з яким я стикаюся з цим (і це не здається представленим на вашому малюнку), це те, що він додає подання безпосередньо на верхню панель навігації, і як результат, це призводить до блокування елементів керування: cl.ly / image / 3d3C2o0N283S
SpacePyro

Ну, тепер я бачу. Має бути[self.navigationController.view insertSubview:backgroundView belowSubview:self.navigationController.navigationBar];
Кевін

Так, я зрозумів, що це ти маєш на увазі. ;) Це, безумовно, дає мені кращий діапазон кольорів для вибору. Отримати яскравість оригінального кольору, ймовірно, буде неможливо, якщо врахувати, що ефект розмитості все-таки все-таки знебарвлює все, що знаходиться під ним. Мені просто доведеться жити з більш темним кольором.
SpacePyro

4

Замість того, щоб створювати ваш об'єкт UIColor у форматі RGB , використовуйте HSB та збільшуйте параметр насичення. ( Подяка Сему Соффу, який описує цей метод тут )

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

Примітка. Це рішення є компромісним і не працює добре для кольорів з високою насиченістю.

Щоб вибрати колір HSB з вашого дизайну, ви можете використовувати такий інструмент, як ColorSnapper, який дозволяє просто скопіювати формат HIC UIColor.

Ви також можете спробувати категорію UIColor ( посилання GitHub ) від David Keegan, щоб змінити існуючі кольори.


3

Проблема тепер була виправлена ​​Apple у новій версії 7.0.3.


1
Так, реалізація їх відтінку кольору, безумовно, змінилася в 7.0.3. Тепер я можу досягти бажаного кольору, просто посилюючи насиченість приблизно на 10-15%. Перш ніж мені також потрібно було розмістити додатковий шар.
Матей Буковинський

Дякую що дали мені знати! Я буду надсилати оновлення до своєї бібліотеки для цього.
SpacePyro

1
І нефіксовано в 7.1> _ <
Лев Натан

1

Я використовував @ рішення aprato, але знайшов кілька випадків кута , де нові шари з нових VCs (наприклад. UINavigationItemButtonViews, UINavigationItemViewsІ т.д.) будуть автоматично вставлені в положення нижче extraColorLayer(що може викликати ті назву або кнопки елементів бути порушені 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
}

Оскільки шари та перегляди не змішані, я не перевантажую addSubView не потрібно
Rob van der Veer

1

Я покращив ваш код у моїй вилці: https://github.com/allenhsu/CRNavigationController

З моєю модифікацією колір результату на екрані (вибраний на білому тлі) буде точно таким же значенням, що передається setBarTintColor. Я думаю, що це дивовижне рішення.


@JordanBrown не тестувались 7,1 та 8
Аллен Хсу

0

Жоден із цих хак не потрібен :). Просто встановіть:

self.navigationController.navigationBar.translucent = NO;

Для iOS 7 напівпрозорість за замовчуванням збережена на рівні ІСТИНА.


17
Але питання вимагає і прозорості.
Лев Натан

:) Дякую, це працювало на мене. Однак є чорна нижня межа 1px під смужкою нав. Чи є спосіб її видалити?
Прітіш Дезай

0

У відповідній примітці ви можете легко встановити колір заголовка тексту (з тінню) за допомогою:

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
Якщо ви намагаєтеся відповідати стилю iOS 7, використання тіні, що випадає, на вашому тексті заголовка, ймовірно, недоречне.
Блокування Ніка

Ви маєте рацію, що в iOS 7 Apple більше не встановлює тіні на їх текстовій панелі. Якщо ви хотіли, щоб користувальницький вигляд хотів, це дасть вам можливість.
bryguy1300

0

Я натрапив на цей Q / A, намагаючись налаштувати рівномірну кольорову панель навігації з прозорістю ЗАБЕЗПЕЧЕНО на iOS 7.

Після деякого експерименту з barTintColor я зрозумів, що дуже простий спосіб мати непрозору навігаційну панель - це зробити єдине піксельне зображення потрібного кольору, зробити з нього розтягуване зображення і встановити його на фоновий малюнок панелі навігації .

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

Три рядки коду, дуже прості і працюють БУТИ на iOS 6 та iOS 7 (barTintColor не підтримується на iOS 6).


0

Відмінна заміна Dropin UINavigationController від Simon Booth, доступна у 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

Як згадував @bernhard вище , можна наситити колір відтінку бар, щоб отримати бажаний зовнішній вигляд панелі навігації.

Я написав утиліту BarTintColorOptimizer для такого типу коригування. Це оптимізує напівпрозорий колір відтінку смуги, щоб фактичний колір бару відповідав бажаному кольору в iOS 7.x та пізніших версіях. Подивіться детальніше на цю відповідь .


-1

Чесно кажучи, вищевказані відповіді можуть бути правильними, але наступний трюк працював для мене дуже легко.

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

Ось зображення, які використовуються для self.imageRedта self.imageBlack.

< self.imageBlack> чорне зображення в цих дужках не буде видно, оскільки воно прозоре :)

< self.imageRed> червоне зображення є в цих дужках.


Це не дає вам розмиття.
Ортвін Генц

-1

чи є спосіб використовувати рішення @aprato без підкласи UINavigationBar.

У моєму проекті головним моїм уявленням є UIViewController.

Проблема полягає в тому, що navigationController є властивістю лише для читання, чи є спосіб використовувати клас для мого проекту, оскільки я не можу використовувати: [[UINavigationController alloc] initWithNavigationBarClass:

Дякую


Чи не могли б ви просто обернути UIViewControllerвсередині UINavigationControllerз [[[UINavigationController alloc] initWithRootViewController:<YourViewController>]? На це також можна краще відповісти як окреме запитання, а не публікувати тут.
SpacePyro

-2

Простий спосіб отримати потрібний вам колір

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

Поки ваше зображення має деяку альфа, прозорість буде працювати, і ви можете встановити альфа, змінивши зображення. Це було додано в iOS7. Ширина та висота для зображення 640x88px для вертикальної (додайте 20 до 88, якщо ви хочете, щоб вона була під рядком стану).


Однак це не зберігає розмитості. Є прозорість, але розмиття немає.
Лев Натан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.