Xcode 11.4。导航栏标题颜色从Storyboard变成了黑色

58
我最近将我的Xcode更新到了11.4版本。当我在设备上运行应用程序时,我注意到从storyboard设置的所有导航项标题都变成了全黑色。 enter image description here 无法通过代码更改,以下代码也不再起作用。
self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]

我只是使用一些iOS 13的东西,比如UINavigationBarAppearance来使其工作。

@available(iOS 13.0, *)
    private func setupNavigationBar() {
        let app = UINavigationBarAppearance()
        app.titleTextAttributes = [.foregroundColor: UIColor.white]
        app.backgroundColor = Constants.Color.barColor
        self.navigationController?.navigationBar.compactAppearance = app
        self.navigationController?.navigationBar.standardAppearance = app
        self.navigationController?.navigationBar.scrollEdgeAppearance = app

        self.navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
    }

有人能解释一下为什么吗?这是一个关键性的漏洞,还是一些新的隐藏特性?


3
我也遇到了同样的问题,但是我找不到正确的解决方法。我认为这可能是一个错误。 :/ - Jordan Favray
苹果。呃。真的吗? - Daniel
尝试这个:https://dev59.com/aVMH5IYBdhLWcg3wtRnA#61003557 - Amrit Tiwari
1
这是关于 Xcode Interface Builder 的 Bug。请将 XCode 更新至 11.4.1 版本。 - NinjaDeveloper
8个回答

39

这对我有帮助,使用UINavigationBarAppearance代替,来自:Customizing Your App’s Navigation Bar

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = UIColor.black
    appearance.titleTextAttributes = [.foregroundColor: UIColor.white] // With a red background, make the title more readable.
    self.navigationBar.standardAppearance = appearance
    self.navigationBar.scrollEdgeAppearance = appearance
    self.navigationBar.compactAppearance = appearance // For iPhone small navigation bar in landscape.
} else {
    self.navigationBar.barTintColor = UIColor.black
    self.navigationBar.tintColor = UIColor.white
    self.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
}
注意:我对 UINavigationController 进行了子类化,并且这是从 viewWillAppear 的覆盖中调用的。
...或者对于全局应用程序 AppDelegate
if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = UIColor.black
    appearance.titleTextAttributes = [
        NSAttributedStringKey.foregroundColor: UIColor.white
    ]

    let buttonAppearance = UIBarButtonItemAppearance()
    buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.white]
    appearance.buttonAppearance = buttonAppearance

    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
    UINavigationBar.appearance().compactAppearance = appearance

    UIBarButtonItem.appearance().tintColor = UIColor.white
} else {
    UINavigationBar.appearance().barTintColor = UIColor.black
    UINavigationBar.appearance().titleTextAttributes = [
        NSAttributedStringKey.foregroundColor: UIColor.white
    ]
    UINavigationBar.appearance().tintColor = UIColor.white

    UIBarButtonItem.appearance().tintColor = UIColor.white
}

...在Objective-C中,用于AppDelegate的全局应用程序范围:

if (@available(iOS 13, *)) {
    UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
    [appearance configureWithOpaqueBackground];
    appearance.backgroundColor = UIColor.whiteColor;
    appearance.titleTextAttributes = titleAttributes;

    UIBarButtonItemAppearance *buttonAppearance = [[UIBarButtonItemAppearance alloc] init];
    buttonAppearance.normal.titleTextAttributes = barButtonItemAttributes;
    appearance.buttonAppearance = buttonAppearance;

    UINavigationBar.appearance.standardAppearance = appearance;
    UINavigationBar.appearance.scrollEdgeAppearance = appearance;
    UINavigationBar.appearance.compactAppearance = appearance;

    [[UINavigationBar appearance] setTintColor:UIColor.blackColor];
} else {
    [[UINavigationBar appearance] setBarTintColor:UIColor.whiteColor];
    [[UINavigationBar appearance] setTintColor:UIColor.blackColor];
    [[UINavigationBar appearance] setTranslucent:false];
    [[UINavigationBar appearance] setTitleTextAttributes: titleAttributes];
    [[UIBarButtonItem appearance] setTitleTextAttributes:barButtonItemAttributes forState:UIControlStateNormal];
}

谢谢,这是正确的答案!在iOS 13上,苹果添加了UINavigationBarAppearance(),在旧版Xcode上没有必要依赖它,但自Xcode 11.4以来,必须使用UINavigationBarAppearance()或标题颜色将始终为黑色。 - Basel
用于大标题的appearance.largeTitleTextAttributes - Skoua
这会将色调变为白色。但我希望我的导航栏保持原来的颜色。如果我注释掉与色调相关的代码行,它仍然会给我一个白色的导航栏。 - JCutting8
谢谢!你帮了我很多! - Mattia Ducci
1
@Richard - 我刚刚添加了Objective-C的答案。抱歉,我直到今天才看到你的评论。 - Stu Carney
显示剩余5条评论

14

在故事板中,将你的导航控制器的“Bar Tint”更改为其“默认”值,然后在代码中,你可以像平常一样更改它。


3
最佳答案。确实如此。 - Vladimir Prigarin
2
这是正确的方式。 - Hugo
1
最佳答案❗️。 - shadowsheep
2
@JCutting8 是的,没错。但是在 Xcode 11.4 中,如果你不在 storyboard 中设置默认颜色,通过编程方式更改它是行不通的。我不知道这是否是一个问题。 - shadowsheep
1
这真是一种魔力! - ekashking
显示剩余2条评论

10

7

不确定这是否是一个bug。

我们修复它的方式是在项目设置中将“状态栏样式”设置为暗色或浅色内容。这将强制状态栏文本颜色呈现某种方式,而不是基于设备处于浅色或深色模式决定。

此外,您需要在Info.plist中将“View controller-based status bar appearance”的值设置为“NO”。如果没有这个值,“状态栏样式”将被覆盖。

接下来,在你的故事板中创建一个自定义导航控制器并实现它。

class CustomNavigationController: UINavigationController {

 override func viewDidLoad() {
    super.viewDidLoad()
    setNavBar()
 }

 func setNavBar() {
    if #available(iOS 13.0, *) {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithOpaqueBackground()
        appearance.backgroundColor = UIColor.blue
        appearance.titleTextAttributes = [.foregroundColor: UIColor.yellow]
        self.navigationBar.standardAppearance = appearance
        self.navigationBar.scrollEdgeAppearance = appearance
        self.navigationBar.compactAppearance = appearance
    } else {
        self.navigationBar.barTintColor = UIColor.blue
        self.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.yellow]
    }
  }
}

*为了让颜色更清晰可见,这里设置了颜色。
我发现把代码放在ViewDidLoad而不是ViewDidAppear中更好,因为我的颜色在初始加载时没有被设置,只有在返回并重新加载后才会被设置。
我还发现这个问题可能与导航栏的“Bar Tint”相关。在我们最初尝试解决它时,我们将“Bar Tint”设置为默认值,这似乎也解决了错误。然而,这使得我们无法得到我们想要的导航栏背景颜色。因此,在我的故事板中,我确保将此值设置为默认值,以防万一。
希望对你有所帮助。

这个是有效的。似乎只是设置全局样式不起作用。 - Mongo
苹果端的一个错误,我无能为力,只能破坏事情 >.< - Michael McKenna

3

0

跟Stu Carney在3/25的回答类似,我加了一些实现细节。

创建一个 UINavigationController 的子类。在 viewWillAppear 中添加以下内容:

let isDarkMode = UserDefaults.standard.bool(forKey: "DarkMode")
let titleColor: UIColor = isDarkMode ? .white : .black
let navBarColor: UIColor = isDarkMode ? .black : .white
let tintColor: UIColor = isDarkMode ? .yellow : .red  //back button text and arrow color, as well as right bar button item

if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    appearance.backgroundColor = navBarColor
    appearance.titleTextAttributes = [.foregroundColor: titleColor]
    appearance.largeTitleTextAttributes = [.foregroundColor: titleColor]

    self.navigationBar.standardAppearance = appearance
    self.navigationBar.scrollEdgeAppearance = appearance
    self.navigationBar.compactAppearance = appearance // For iPhone small navigation bar in landscape.

    self.navigationBar.tintColor = tintColor //changes back button text and arrow color, as well as right bar button item
} else {
    self.navigationBar.barTintColor = navBarColor
    self.navigationBar.tintColor = tintColor
    self.navigationBar.titleTextAttributes = [.foregroundColor: titleColor]
    self.navigationBar.largeTitleTextAttributes = [.foregroundColor: titleColor]
}

然后覆盖 preferredStatusBarStyle

override var preferredStatusBarStyle: UIStatusBarStyle {
    let isDarkMode = UserDefaults.standard.bool(forKey: "DarkMode")
    return isDarkMode ? .lightContent : .default
}

如果您想动态更新导航栏和状态栏,例如从UISwitch IBAction或选择器方法中,可以添加以下内容:
navigationController?.loadView()
navigationController?.topViewController?.setNeedsStatusBarAppearanceUpdate()

此外,请确保在IB中将所有导航栏和按钮设置为默认颜色。Xcode似乎存在一个错误,即IB颜色会覆盖程序设置的颜色。

0

我曾经遇到同样的问题,想着编码不是解决方案,肯定有其他方法。后来发现,在Storyboard属性检查器中,在导航栏-外观下任意选择一个选项都会使标题变黑。所以取消所有选中。但我不确定如何保持滚动边缘选项以将状态栏颜色化,同时仍然能够得到标题的颜色。


0
在我的情况下,当我将Xcode从11.3升级到11.4后,出现了这个错误。 因此,我必须更改我的代码以便在导航栏中设置图像作为背景。
if #available(iOS 13.0, *) {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithOpaqueBackground()
    let backgroundImage = UIImage(named: "{NAVBAR_IMAGE_NAME}")?.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch)
    appearance.backgroundImage = backgroundImage
    self.navigationController?.navigationBar.compactAppearance = appearance
    self.navigationController?.navigationBar.standardAppearance = appearance
    self.navigationController?.navigationBar.scrollEdgeAppearance = appearance        
} else {
    self.navigationController?.navigationBar.barTintColor = Utils.themeColor
    let backgroundImage = UIImage(named: "{NAVBAR_IMAGE_NAME}")?.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch)
    self.navigationController?.navigationBar.setBackgroundImage(backgroundImage, for: .default)
    self.navigationController?.navigationBar.shadowImage = UIImage()
}

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