iOS 7: 禁用整个应用程序的UINavigationBar半透明效果

55

有没有一种方法可以禁用整个应用程序的UINavigationBar半透明效果?

我知道使用[self.navigationController.navigationBar setTranslucent:NO]可以解决单个控制器的问题,但我的应用程序中有很多UINavigationBars,这是一个非常繁琐的解决方案。

我尝试过[[UINavigationBar appearance]setTranslucent:NO],但该功能令人惊讶地不被支持。执行该操作会导致Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** Illegal property type, c for appearance setter, _installAppearanceSwizzlesForSetter:'

如果必须的话,我可以逐个设置禁用半透明效果来解决问题,但肯定有更优雅的解决方案...


你在使用故事板吗? - BlueBear
很遗憾,我不是。 - MikeS
4
有没有一种方法可以让我的观点以合理的方式布局,而无需关闭半透明效果?这太荒谬了。 - powerj1984
9个回答

33
如果您将堆栈中第一个导航栏的半透明属性设置为false[self.navigationController.navigationBar setTranslucent:NO],则这将反映在所有推送到该堆栈的后续NavigationViewController中。

2
如果您正在使用Storyboard,请从UINavigationController中取消选择透明度。 - Roshan
2
如果您显示任何模态视图控制器或任何不在导航控制器内发生的内容,则此解决方案不完整。 - atreat

19

如果您想将此样式应用于整个应用程序,则可以使用以下 Swift 解决方案。

AppDelegate 类中,将以下内容添加到 didFinishLaunchingWithOptions 中:

对于 Swift 2:

UINavigationBar.appearance().translucent = false

对于 Swift 3+:

UINavigationBar.appearance().isTranslucent = false

8
在 iOS 8 及以上版本中,在 appDelegatedidFinishLaunchingWithOptions 方法中加入以下代码即可实现,看起来非常简单。
[[UINavigationBar appearance] setTranslucent:NO];

我不确定为什么有人给了这个负分,我使用它完美地工作了!我投了赞成票! - Septronic
无论如何,还是谢谢你。 - Septronic

3

我认为你说得对,这个属性没有出现代理。你是在使用UINavigationControllers或UINavigationBar对象吗?如果你在使用UINavigationBars,你可以创建一个非透明的导航栏子类。

头文件:

#import <UIKit/UIKit.h>

@interface ABCNonTranslucentNavBar : UINavigationBar

@end

实现文件:

#import "ABCNonTranslucentNavBar.h"

@implementation ABCNonTranslucentNavBar

- (void)drawRect:(CGRect)rect
{
  [self setTranslucent:NO];
}

只需用您的子类替换UINavigationBars即可。您也可以使用一个子类化的UINavigationController进行类似的操作。


1
这绝对是一个有趣的想法,但有点麻烦。也许有更简单的方法...?无论现在的答案如何,如果iOS 7.1没有添加半透明外观代理,我会感到震惊的。另外,回答你的问题,我正在使用UINavigationControllers,而不仅仅是导航栏。 - MikeS
使用方法混淆技术,然后在viewDidLoad中进行修复,这个方案怎么样? - huggie
您还可以子类化UINavigationController并覆盖指定的初始化方法,以设置self.navigationBar.translucent = NO。 - Sam Grossberg
7
这样做是在-drawRect:方法中...看着你的应用程序崩溃很有趣 ;) - Christian Schnorr

3

如果有人仍然在与此问题纠缠,请尝试以下方法。

您可以通过指定不存在的图像来欺骗它,这将使导航栏及其工具栏变得不透明。

[[UIToolbar appearance] setBackgroundColor:[UIColor colorWithRed:219.0/255.0 green:67.0/255.0 blue:67.0/255.0 alpha:1.0]];

[[UIToolbar appearance] setBackgroundImage:[[UIImage alloc] init] forToolbarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];

当将此应用于UINavigationBar时,您最终会得到一个黑色状态栏 :( - Sjoerd Perfors

2
我知道这个内容比较旧,但对某些人有用;你可以使用一个类别,并在其中设置属性[translucent][1]
@implementation UINavigationBar (MakeTranslucent)

-(void)willMoveToWindow:(UIWindow *)newWindow {
    [super willMoveToWindow:newWindow];


    self.translucent = NO;
}
@end
  • 我使用了willMoveToWindow方法,但我不确定这是否是一个好主意,所以请自行决定是否使用。

1
请注意,这样做是危险的,因为它不会调用原始的UINavigationBar willMoveToWindow: 实现。类别方法完全替换了该方法的原始实现,因此您实际上跳过了原始的UINavigationBar实现并直接调用了UIView的实现。https://dev59.com/KW025IYBdhLWcg3wLitX - Andy Riordan
使用分类覆盖方法是一个糟糕的想法。实际上,在iOS 8.3中,覆盖类方法的分类方法似乎不会被调用。 - atreat

1

请参见UIKit代码文档中的摘录:

/*
     New behavior on iOS 7.
     Default is YES.
     You may force an opaque background by setting the property to NO.
     If the navigation bar has a custom background image, the default is inferred 
     from the alpha values of the image—YES if it has any pixel with alpha < 1.0
     If you send setTranslucent:YES to a bar with an opaque custom background image
     it will apply a system opacity less than 1.0 to the image.
     If you send setTranslucent:NO to a bar with a translucent custom background image
     it will provide an opaque background for the image using the bar's barTintColor if defined, or black
     for UIBarStyleBlack or white for UIBarStyleDefault if barTintColor is nil.
     */

正确的 Swift 4 解决方案是

UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().backgroundColor = .white

0

我认为外观 API 不支持导航栏的半透明属性。 但是您可以像这样为整个应用程序执行此操作,请查看此代码--

这里的菜单屏幕是根视图控制器。

MenuScreen *ms = [[MenuScreen alloc]initWithNibName:@"MenuScreen" bundle:nil];

UINavigationController *nv = [[UINavigationController alloc]initWithRootViewController:ms];

//This will set property for whole App.
[nv.navigationBar setTranslucent:NO];

self.window.rootViewController = nv ;

它只会将其设置为这个导航栈的半透明。如果您有任何模态导航控制器、多个选项卡或任何其他更复杂的导航模式,它将无法工作。 - Daniel Rinser
所以你需要像这样逐个设置每个堆栈。 - kshitij godara
是的,当然可以。但是这个问题的重点在于是否有一种方法可以全局设置它(例如通过UIAppearance),而这恰恰不是你正在做的事情。此外,你在回答中说它“将被设置为整个应用程序”,这是不正确的。 - Daniel Rinser

-3
如果您不使用故事板而是使用IB,那么请将您的MainWindows.xib的导航栏样式设置为非半透明,并将颜色设置为非透明颜色。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接