升级到Xcode 5.1和iOS 7.1后,在segue转换期间导航栏出现了黑暗阴影。

95

当我在主-细节导航控制器的父子控制器之间来回导航时,我会看到导航栏顶部右侧有一个深色阴影。这是在我升级到Xcode 5.1后出现的。它感觉很粗糙,很分散注意力。我该如何摆脱它?

13个回答

145
self.navigationController.view.backgroundColor = [UIColor whiteColor];

我通过设置导航控制器视图的背景颜色来解决了这个问题。


这个答案实际上非常好。由于某种原因,Interface Builder不允许您访问导航控制器的视图,但似乎仍然存在一个名为darkColor的视图,并导致了这个问题。 - superarts.org
1
这是一个很好的答案,因为它不仅允许工具栏保持半透明,而且还能避免导航控制器中那个难看的黑色部分渗透出来。只是希望能在故事板中设置它的方式。 - dimiguel
没错。我时不时地会想到这个问题,并对其他建议关闭导航栏透明度的答案感到有些失望,因为基本上他们是通过禁用一个功能来解决这个问题,而这个答案指出了实际的解决方法。很遗憾,在Xcode 7 / iOS 9中这种行为仍然存在。 - superarts.org
1
抱歉,我对这个答案进行了负评,因为窗口背景不是这个问题的根本原因。请查看我附加的截图:http://imgur.com/a/SH5Dp 你会发现问题仍然存在,只是深色阴影被白色取代了,我猜测详情控制器被“裁剪”或者其他方式,使其在导航栏下面不绘制任何东西。 - mariotaku
1
如果根控制器是UITabBarController,则tabBarController?.view.backgroundColor = UIColor.white。 - Vishal Singh

57
self.navigationController.navigationBar.translucent = NO; 

适用于较新的 Swift 版本:

navigationController?.navigationBar.isTranslucent = false

你把这个放在哪里了? - Zorayr
在主视图控制器的ViewDidLoad方法中 - Nihat
在 viewDidAppear 中添加。 - Abdul Waheed
1
@Annjawn,navigationController.view.backgroundColor = .white在iOS 12上可行。移除导航栏的半透明效果可能在某些情况下不合适,但黑色阴影则可以使用。 - Alex Motor
上帝保佑你健康。 - Booharin
显示剩余2条评论

37

nonamelive的回答非常完美。要在界面生成器中实现相同效果并继续保持半透明,请选中导航控制器并设置用户定义的运行时属性view.backgroundColor如截图所示(在“Identity Inspector”中)。对于所有显示此问题的导航控制器都需要重复此步骤。

似乎整个问题是因为UINavigationController的黑色(或实际上是没有颜色)在动画开始时通过CoreGraphics泄漏出来。因此,将其设置为白色将防止这种情况发生。

Identity Inspector -> User Defined Runtime Attributes


1
我更喜欢这种方法,让Interface Builder尽可能处理UI相关的事情。 - DazChong
iOS 8.4 没有帮助。 - Yaroslav Dukal
3
可与Xcode 8.3.3完美配合使用。强调一下,必须在UINavigationController上设置,而不是在viewController上。 - jungledev
我在一个选项卡控制器中使用了导航控制器,并且在其中一个导航控制器的视图控制器上使用了“推送时隐藏底部栏”,导致两个栏(顶部和底部)都出现了阴影。将导航控制器的白色背景设置为解决了这个问题。谢谢! - nh32rg

6
这似乎是在iOS 7.1中引入的错误。在我的情况下,它是由放置在导航栏直接下方的UIToolbar引起的。暗阴影也会出现在半透明的选项卡栏中。
这个阴影似乎是由UIToolbar的背景视图引起的。我现在在具有工具栏的视图控制器中使用此解决方法,它在过渡期间隐藏了工具栏的背景视图:
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    UIView *toolbarBackgroundView = [self.toolbar findViewRecursively:^BOOL(UIView *subview, BOOL *stop) {
        BOOL isToolbarBackgroundView = ([subview isKindOfClass:[UIImageView class]]
                                        && [NSStringFromClass(subview.class) isEqualToString:@"_UIToolbarBackground"]);
        if (isToolbarBackgroundView) {
            *stop = YES;
        }
        return (! isToolbarBackgroundView);
    }];
    if (toolbarBackgroundView) {
        // fade toolbar background view back in
        [UIView animateWithDuration:0.1f animations:^{
            toolbarBackgroundView.alpha = 1.0f;
        }];
    }
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    UIView *toolbarBackgroundView = [self.toolbar findViewRecursively:^BOOL(UIView *subview, BOOL *stop) {
        BOOL isToolbarBackgroundView = ([subview isKindOfClass:[UIImageView class]]
                                        && [NSStringFromClass(subview.class) isEqualToString:@"_UIToolbarBackground"]);
        if (isToolbarBackgroundView) {
            *stop = YES;
        }
        return (! isToolbarBackgroundView);
    }];
    if (toolbarBackgroundView) {
        // hide toolbar background view
        toolbarBackgroundView.alpha = 0.0f;
    }
}

这是[UIView findViewRecursively:]代码的内容。
@interface UIView (FindSubview)

- (UIView*)findViewRecursively:(BOOL(^)(UIView* subview, BOOL* stop))recurse;

@end

@implementation UIView (FindSubview)

- (UIView*)findViewRecursively:(BOOL(^)(UIView* subview, BOOL* stop))recurse {
    for (UIView* subview in self.subviews) {
        BOOL stop = NO;
        if (recurse(subview, &stop)) {
            UIView* view = [subview findViewRecursively:recurse];
            if (view) return view;
        } else if (stop) {
            return subview;
        }
    }
    return nil;
}

@end

我提交了这个Radar:http://openradar.appspot.com/16418845

(意思是作者提交了一个关于it技术的问题反馈链接)

2
如果您不需要半透明的导航栏,那么您的解决方案就很好。 - tom
有一个更简单的方法来获取 backgroundView[self.toolbar valueForKey:@"_backgroundView"]。请注意,这是一个私有API,但我认为你不会被苹果抓到,因为 _backgroundView 只是一个通用名称。 - nonamelive
这个答案提示了我需要做什么。在我的情况下,只需在界面构建器中取消选中UIToolbar上的半透明选项即可。 - Greg W

5
这对我在Swift中非常有效。
在AppDelegate的didFinishLaunchingWithOptions方法中,我设置了以下内容:
UIApplication.shared.windows.first?.backgroundColor = .white

5

这对我来说在上都可以工作,并且支持浅色深色主题,也适用于旧版iOS。

将以下代码添加到AppDelegate的application(didFinishLaunchingWithOptions)方法中:

if #available(iOS 13.0, *) {
    window?.backgroundColor = UIColor.systemBackground
} else {
    window?.backgroundColor = UIColor.white
}

2
我也尝试过这种方法,但是在默认模式下呈现视图控制器时遇到了问题。然后你会看到窗口的白色背景而不是黑色的。那看起来很奇怪。你能否提供任何想法来克服这种情况? - varun v nair

4

似乎任何半透明的工具栏(TabBar或ToolBar)都会出现这种情况。
因此,一种解决方法是设置_tabBar.translucent = NO;(在我的情况下)。这可以防止顶部导航栏下的不必要阴影,同时保持导航栏半透明。不幸的是,底部工具栏不再是半透明的。

它可以重新设置为半透明,但所有这些都必须在整个推送动画完成后才能发生,因此切换此属性非常明显。

然而,如果底部工具栏也必须是半透明的,而我不希望用户看到这种变化,我使用以下方法进行解决:

/*  create a simple quick animation of the bottom bar
    just before pushing the new controller */
[UIView animateWithDuration:0.1
                 animations:^{
                     _tabBar.barTintColor = [UIColor colorWithWhite:0.97254901960784 alpha:1.0]; // this is the closest color for my case
                     _tabBar.translucent = NO;
                 } completion:^(BOOL finished) {
                     /* now when the animation that makes the bar not translucent
                        is finished we can push the new controller
                        the controller is instantiated before the animation code */
                     [self.navigationController pushViewController:controller animated:YES];
                 }];

然后在 viewDidAppear: 中,我只需将其恢复回来:
[UIView animateWithDuration:0.1
             animations:^{
                     _tabBar.barTintColor = nil;
                     _tabBar.translucent = YES;
                 }];

外观上只有一点点变化,但几乎不会被注意到,而且比导航栏下面有阴影要好得多。

希望这能帮助其他人在苹果修复此行为之前保持条形透明,因为在某些情况下,栏目确实应该被隐藏,尤其是对于UITabBar


我通过采用@manmal的解决方案成功修复了这个问题——在故事板中为您的UITabBarController定义运行时属性view.backgroundColor,并将其设置为白色。 - jamesk

3
self.navigationController!.navigationBar.translucent = false;

这对我很有效,将其放入您推送新 ViewController 的函数中。

疯狂的是,在所有答案中,将其放置在推到下一个VC的函数中的想法是最好的! - Coltuxumab

3
这是我的变体……它比汤姆的回答需要更少的代码,并且更有效。如果你想要一个半透明的导航栏,同时还想解决阴影问题,可以采用这种方法。
在源View Controller中(嵌入在导航控制器中)…
- (void)viewDidAppear:(BOOL)animated
{
     self.navigationController.navigationBar.translucent = YES;
}

并且

 - (void)viewWillDisappear:(BOOL)animated
 {
     self.navigationController.navigationBar.translucent = NO;
 }

结果与Tom执行的操作相同(从视觉上,对终端用户而言),并且更容易实现。希望这可以帮到您...


3
以下内容同样适用且将导航栏保持透明:
[UIApplication sharedApplication].keyWindow.backgroundColor = [UIColor whiteColor];

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