Xcode 11.4。故事板中导航的标题颜色变黑

Xcode 11.4. Navigation's Title Color gone BLACK from storyboard

我最近将 Xcode 更新到了 11.4。当我 运行 设备上的应用程序时,我注意到我的所有导航项的标题在从情节提要中设置时都变成了黑色。

您不能从代码中更改两者,以下代码行不再起作用

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

谁能解释一下为什么???这是一个严重的错误,还是一些新的隐藏功能?

不知道是不是bug。

我们修复它的方法是在项目设置中将 "Status Bar Style" 设置为深色或浅色内容。这将以某种方式强制状态栏文本颜色,而不是根据处于浅色或深色模式的设备来确定。

此外,您需要在 Info.plist 中将值 "View controller-based status bar appearance" 设置为 "NO"。如果没有该值,"Status Bar style" 将被覆盖。

接下来创建一个自定义导航控制器并在您的情节提要中实现它。

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" 设置为默认值,这似乎也解决了错误。但是,它成功了,所以我们无法获得我们想要的 NavBar 背景颜色。因此,在我的故事板中,我确保将此值设置为默认值只是为了更好地衡量。

希望对您有所帮助

这为我修复了它,改为使用 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
}

...对于 AppDelegate,应用程序范围,在 Objective-C:

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

在 Storyboard 上,将导航控制器的 "Bar Tint" 更改为其 "Default" 值,然后在您的代码中,您可以像往常一样更改它。

与 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 颜色会覆盖以编程方式设置的颜色。

Apple 终于在 11.4.1 版本中修复了它

https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_1_release_notes

不需要 workaround.it 是 Xcode Interface Builder 中的错误。 Apple 发布更新 Xcode 11.4.1

来自 Apple 开发人员发行说明

Interface Builder

Fixed an issue that caused some UINavigationBar appearance properties set in storyboard and XIB documents to be ignored when building with Xcode 11.4. (60883063) (FB7639654)

https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_1_release_notes

就我而言,在我将 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()
}