ChatGPT解决这个技术问题 Extra ChatGPT

为 iOS 7 半透明 UINavigationBar 实现明亮、生动的色彩

iOS 7.1 更新:在此更新中,修改 UINavigationBar 中的 alpha 通道的解决方法似乎已被忽略。现在,最好的解决方案似乎是“处理它”,并希望你选择的任何颜色都能呈现半透明的效果。我仍在寻找解决此问题的方法。

iOS 7.0.3 更新GitHub library we created 已更新,可在使用 iOS 7.0.3 时略微解决此问题。不幸的是,没有神奇的公式来支持在 iOS 7.0.2 及更早版本和 iOS 7.0.3 中创建的两种颜色。似乎Apple提高了饱和度,但以不透明度为代价(因为模糊的半透明取决于不透明度级别)。我和其他一些人正在努力为此创建一个更好的解决方案。

我相信很多人已经遇到过这样的问题:iOS 7 倾向于降低半透明 UINavigationBar 的颜色饱和度。

我的目标是实现一个具有这种色调但半透明的 UINavigationBar:

https://i.stack.imgur.com/9RjRa.png

但是,通过半透明,我得到了这个。背景视图是白色的,我知道这会使这个视图更亮一点:

https://i.stack.imgur.com/RA5wt.png

有没有办法在保持半透明的同时达到原始颜色?我注意到 Facebook 已经能够让他们的栏变成丰富的蓝色,如下所示:

https://i.stack.imgur.com/C5jXs.png

..所以我知道必须有某种方式。背景视图显然在这里有所作为,但它们的大部分内容也是灰色/白色的。似乎无论您输入哪种条形色调颜色,您都无法在半透明下获得鲜艳的色彩。

更新了解决方案。

这是我最终提出的解决方案。我采用了 aprato 的解决方案,然后将自定义 UINavigationBar 包含在 UINavigationController 子类中。 I have created a repository that has this implementation listed below, along with an example app

////////////////////////////
// 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 导航栏不透明
它绝对是半透明的;请查看我编辑的回复。
@Odelya - 这不是获得正确颜色的解决方案,而是在 iOS 7 中暴露于半透明时尽可能校正 UINavigationBar 亮度的解决方案。

A
Anthony

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;

布局子视图

  [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 子类中。对于那些有兴趣在 UINavigationController 中包含自定义 UINavigationBar 的人来说,这是其中的 gist
@Jeremy 喜欢 SpacePyro 我有一个导航控制器子类(就像我使用 pre 7 进行 UIAppearance 定位的栏一样)覆盖 initWithRootViewController 以使用它。我已经更新了我的要点
嗯……好吧……我想我需要在整个测试项目中看到这一点才能完全理解你的意思。我能够在下面复制 timeuser 的示例,但我仍然对这个有点不满意。
@Mr.T 谢谢!当我写它的时候还没有推送 :) 但我现在已经更新了它,添加了 UIAppearance 以实现不透明度和对 NSCoding 的支持
B
Bhavesh

iOS 7.0 中条形的 tintColor 行为已更改。它不再影响栏的背景,其行为与添加到 UIView 的 tintColor 属性的描述相同。要为栏的背景着色,请使用 -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)

J
Jamie Hamick

我没有想出这个解决方案,但它似乎工作得很好。我刚刚将它添加到 UINavigationController 子类的 viewDidLoad 中。

来源: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];

看起来在将一个新的视图控制器推到导航控制器上之后,任何条形按钮项都会移动到这个透明层之下。
标题也会被这个透明层遮住。
我写了这个要点。评论是对的;当一个新的视图控制器被按下时,按钮项被推到下面,或者子层继承了 colourView 的 alpha。我分叉了另一个答案,并将一些东西固定到一个新的临时课程中:github.com/alanzeino/AZColoredNavigationBar
我可以通过选择半透明黑色导航栏样式将文本设置为白色......这对我来说是诀窍。同时设置 yourBar.tintColor = [UIColor whiteColor];用于顶部的其他自定义按钮。
C
Community

一种低保真方式可能是将作为导航栏高度的 UIView 固定到导航栏后面的视图顶部。使该视图与导航栏颜色相同,但使用 alpha 直到获得所需的效果:

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 后面

https://i.stack.imgur.com/c3CMI.png

(将颜色从较低的示例更改为强调透明度。透明度/模糊在移动时更加明显。)

UINavigationBar 子类化并将相同的视图放在背景上方但在其他所有内容之后可能会获得类似的结果,同时不那么 hacky。

我见过的另一个解决方案是使用 UINavigationBar 的 alpha:

self.navigationController.navigationBar.alpha = 0.5f;

编辑:实际上,经过测试,这似乎没有提供预期的行为(或任何行为):

.8 阿尔法

https://i.stack.imgur.com/nMhLz.png

未调整的阿尔法

https://i.stack.imgur.com/rorI0.png

显然,您只想在 iOS 7 设备上执行此操作。因此,在您实施其中任何一项之前,add some version check


我支持更新 alpha 和 tintColor 以获得您正在寻找的颜色的方法。
如果您可以通过这种侵入性较小的方式获得所需的效果,那么完全可以。但我不确定它会有多有效。
我遇到的唯一问题(您的图片中似乎没有显示)是它直接在导航栏顶部添加视图,因此导致控件被阻止:cl.ly/image/3d3C2o0N283S
哎呀,现在我明白了。应该是 [self.navigationController.view insertSubview:backgroundView belowSubview:self.navigationController.navigationBar];
是的,我想这就是你的意思。 ;) 这绝对让我有更好的颜色可供选择。考虑到模糊效果仍然会降低其下的任何内容的饱和度,获得原始颜色的活力可能是不可能的。我现在只能忍受较深的颜色。
b
bernhard

不要以 RGB 格式创建 UIColor 对象,而是使用 HSB 并增加饱和度参数。 (归功于描述此方法 hereSam Soffes

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

注意:此解决方案是一种折衷方案,不适用于高饱和度的颜色。

要从您的设计中选择 HSB 颜色,您可以使用像 ColorSnapper 这样的工具,它允许您简单地复制 UIColor HSB 格式。

您还可以尝试使用 David Keegan 中的 UIColor 类别 (GitHub Link) 来修改现有颜色。


s
smad

Apple 已在新的 7.0.3 版本中修复了该问题。


是的,他们的 tint color 实现在 7.0.3 中肯定发生了变化。我现在可以通过将饱和度提高约 10-15% 来实现我想要的颜色。在我还需要添加额外的图层之前。
谢谢你让我知道!为此,我将向我的图书馆推送更新。
并且在 7.1 中未修复>_<
M
Mr. T

我使用了@aprato 的解决方案,但发现了一些极端情况,其中来自新 VC 的新层(例如 UINavigationItemButtonViewsUINavigationItemViews 等)会自动插入到 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
A
Allen Hsu

我在我的 fork 中改进了您的代码:https://github.com/allenhsu/CRNavigationController

通过我的修改,屏幕上的结果颜色(在白色背景上选取)将与传递给 setBarTintColor 的值完全相同。我认为这是一个了不起的解决方案。


@JordanBrown 未在 7.1 和 8 上测试
P
Peter Mortensen

这些黑客都不是必需的:)。简单设置:

self.navigationController.navigationBar.translucent = NO;

对于 iOS 7,默认的半透明保持为 TRUE。


但这个问题也需要半透明。
:) 谢谢,它对我有用。但是导航栏下方有一个 1px 黑色底边框。有什么办法可以去掉吗?
b
bryguy1300

在相关说明中,您可以通过以下方式轻松设置标题文本颜色(带阴影):

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

如果您尝试匹配 iOS 7 的样式,则在标题文本上使用阴影可能是不合适的。
您是对的,在 iOS 7 中,Apple 不再在其导航栏文本上设置阴影。但是,如果您想要自定义外观,这将为您提供选择。
b
bizz84

我在尝试设置一个统一颜色的导航栏时遇到了这个 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(iOS 6 不支持 barTintColor)。


D
DoctorG

GitHub Here GitHub - C360NavigationBar 上的 Simon Booth 提供了一个很棒的 Dropin UINavigationController 替代品

如果您向后支持 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;

除非我遗漏了什么,否则这个图书馆的酒吧不是半透明的。
C
Community

作为@bernhard mentioned above,可以使条形颜色饱和以获得所需的导航栏外观。

我为这种调整写了一个BarTintColorOptimizer utility。它优化了半透明条的色调颜色,使条的实际颜色与 iOS 7.x 及更高版本中所需的颜色相匹配。查看 this answer 了解详情。


S
Sagar Kothari

坦率地说,以上答案可能是正确的,但以下技巧对我来说很容易。

// 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.imageRedself.imageBlack 的图像。

https://i.stack.imgur.com/EFhlm.png

https://i.stack.imgur.com/rlgmu.png


这不会让你模糊。
A
Ashish Kakkad

有没有办法在不继承 UINavigationBar 的情况下使用 @aprato 解决方案。

在我的项目中,我的主视图是 UIViewController。

问题是navigationController是一个只读属性,有没有办法在我的项目中使用你的类,因为我不能使用:[[UINavigationController alloc] initWithNavigationBarClass:

谢谢


您不能将您的 UIViewController 包装在带有 [[[UINavigationController alloc] initWithRootViewController:<YourViewController>]UINavigationController 中吗?这也可能作为一个单独的问题得到更好的回答,而不是在此处发布。
C
Carter

获得所需颜色的一种简单方法是使用

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

只要您的图像有一些 alpha,半透明就会起作用,您可以通过更改图像来设置 alpha。这只是在 iOS7 中添加的。图像的宽度和高度是垂直的 640x88 像素(如果您希望它位于状态栏下方,则将 20 添加到 88)。


然而,这不会保留模糊。有透明度,但没有模糊。