Ios Can';t更改UINavigationBar提示颜色

Ios Can';t更改UINavigationBar提示颜色,ios,swift,cocoa-touch,uikit,uinavigationbar,Ios,Swift,Cocoa Touch,Uikit,Uinavigationbar,我无法更改导航栏上的提示颜色。我在viewDidLoad中尝试了下面的代码,但什么也没发生 self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white] 我错过什么了吗?上面的代码错了吗?试试看:-> navController.navigationBar.titleTextAttributes = [NSAttribu

我无法更改导航栏上的提示颜色。我在
viewDidLoad
中尝试了下面的代码,但什么也没发生

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

我错过什么了吗?上面的代码错了吗?

试试看:->

navController.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.red]

看来你在这件事上是对的。您需要使用
UIAppearance
在iOS 11上设置提示文本的样式

我已经提交了雷达文件34758558,
titleTextAttributes
属性在iOS 11中停止了对提示符的操作

好消息是,我们可以通过使用Xcode的view hierarchy debugger发现一些变通方法:

提示只是一个UILabel。如果我们在包含InstanceSof:时使用UIAppearance的
,我们可以很容易地按照我们想要的方式更新颜色

如果仔细观察,您会注意到UILabel上还有一个包装器视图。它有自己的类,可能会响应UIE外观

我建议坚持使用更通用的解决方案,因为它不使用私有API。(应用程序审查等)查看这两种解决方案中的任何一种都能带来什么:


当iOS 11将barStyle设置为黑色时,我能够将提示颜色设置为白色。我使用外观代理设置其他颜色属性(如所需的背景色):

myNavbar.barStyle = UIBarStyleBlack; // Objective-C
myNavbar.barStyle = .black // Swift

Moshe的第一个答案对我不起作用,因为它改变了系统VCs内部的标签,如邮件和文本合成VCs。我可以改变那些导航条的背景,但那会打开一整罐蠕虫。我不想使用私有类,所以我只更改了自定义导航栏子类中包含的UILabel

UILabel.appearance(whenContainedInInstancesOf: [NavigationBar.self]).textColor = UIColor.white
你可以用

for view in self.navigationController?.navigationBar.subviews ?? [] {
    let subviews = view.subviews
    if subviews.count > 0, let label = subviews[0] as? UILabel {
        label.textColor = UIColor.white
        label.backgroundColor = UIColor.red
    }
}

这将是一个临时的解决办法,直到他们将其修复为支持新旧iOS的更复杂版本

    func updatePromptUI(for state: State) {
    if (state != .Online) {
        //workaround for SOFT-7019 (iOS 11 bug - Offline message has transparent background)
        if #available(iOS 11.0, *) {
            showPromptView()
        } else {
            showOldPromptView()
        }
    }
    else {
        self.navigationItem.prompt = nil
        if #available(iOS 11.0, *) {
            self.removePromptView()
        } else {
            self.navigationController?.navigationBar.titleTextAttributes = nil
            self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor:UIColor.lightGray]
        }
    }
}

private func showOldPromptView() {
    self.navigationItem.prompt = "Network Offline. Some actions may be unavailable."
    let navbarFont = UIFont.systemFont(ofSize: 16)
    self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.font: navbarFont, NSAttributedStringKey.foregroundColor:UIColor.white]
}

private func showPromptView() {
    self.navigationItem.prompt = String()
    self.removePromptView()

    let promptView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 18))
    promptView.backgroundColor = .red
    let promptLabel = UILabel(frame: CGRect(x: 0, y: 2, width: promptView.frame.width, height: 14))
    promptLabel.text = "Network Offline. Some actions may be unavailable."
    promptLabel.textColor = .white
    promptLabel.textAlignment = .center
    promptLabel.font = promptLabel.font.withSize(13)
    promptView.addSubview(promptLabel)
    self.navigationController?.navigationBar.addSubview(promptView)
}

private func removePromptView() {
    for view in self.navigationController?.navigationBar.subviews ?? [] {
        view.removeFromSuperview()
    }
}

我找到了iOS 11的下一个解决方案。 您需要设置为
viewDidLoad
navigationItem.prompt=UINavigationController.fakeUniqueText
然后再放下一件事

navigationController?.promptabel(完成:{label in
标签?.textColor=.white
标签?.font=font.regularFont(大小:.p12)
})
扩展UINavigationController{
public static let fakeUniqueText=“\n\n\n\n”
func promptLabel(完成:@escaping(UILabel?)->Void){
gloabathread(后:0.5){[弱自我]在
守卫让'self`=self-else{
返回
}
让label=self.findPromptLabel(位于:self.navigationBar)
主线{
完成(标签)
}
}
}
func FindComptLabel(在视图中:UIView)->UILabel{
如果let label=查看为UILabel{
如果label.text==UINavigationController.fakeUniqueText{
退货标签
}
}
变量标签:UILabel?
view.subviews.forEach{中的子视图
如果let promptLabel=findPromptLabel(at:subview){
标签=即时标签
}
}
退货标签
}
}
public func主线程(u完成:@escaping SimpleCompletion){
DispatchQueue.main.async(执行:完成)
}
公共函数gloabalThread(之后:Double,完成:@escaping SimpleCompletion){
DispatchQueue.global().asyncAfter(截止日期:.now()+之后){
完成()
}

}
我建议使用自定义的
UINavigationBar
子类并覆盖
layoutSubviews

- (void)layoutSubviews {
    [super layoutSubviews];

    if (self.topItem.prompt) {
        UILabel *promptLabel = [[self recursiveSubviewsOfKind:UILabel.class] selectFirstObjectUsingBlock:^BOOL(UILabel *label) {
            return [label.text isEqualToString:self.topItem.prompt];
        }];
        promptLabel.textColor = self.tintColor;
    }
}
基本上,我正在枚举子视图层次结构中的所有UILabel,并检查它们的文本是否与提示文本匹配。然后我们将textColor设置为tintColor(可以随意使用自定义颜色)。这样,我们就不必硬编码私有的
\u uinavigationBarModernComptView
类作为提示标签的superview。因此,该代码更能证明未来

将代码转换为Swift并实现助手方法
recursiveSubviewsOfKind:
selectFirstObjectUsingBlock:
留给读者作为练习您可以尝试以下方法:

import UIKit
class ViewController: UITableViewController {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        updatePrompt()
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        updatePrompt()
    }
    func updatePrompt() {
        navigationItem.prompt = " "
        for view in navigationController?.navigationBar.subviews ?? [] where NSStringFromClass(view.classForCoder) == "_UINavigationBarModernPromptView" {
            if let prompt = view.subviews.first as? UILabel {
                prompt.text = "Hello Red Prompt"
                prompt.textColor = .red
            }
        }
        navigationItem.title = "This is the title (Another color)"
    }
}

在swift 4中尝试
navigationController?.navigationBar.titleTextAttributes=[NSForegroundColorAttributeName:UIColor.white]
的titleTextAttributes
类型为
[NSAttributedStringKey:Any]?
NSForegroundColorAttributeName
是一个字符串,因此不会以这种方式生成。在Swift 4中,titleTextAttributes的类型为
[NSAttributedStringKey:Any]?
NSAttributedStringKey.foregroundColor.rawValue是一个
字符串
。您的代码将不会在Swift 4.navigationController?.navigationBar.PrefersTargetTitles=true编辑中编译。如果需要更改大标题的文本属性,则需要在UINavigationBar上使用新的LarGetTitleTextAttributes属性:UINavigationBar.appearance().LarGetTitleTextAttributes=[NSForegroundColorAttributeName:UIColor.white]它似乎在iOS11(xCode 9.0.0)上不起作用.大标题更改颜色,但不更改提示!可能值得明确指出,将栏样式设置为.black并不意味着您的导航栏颜色将为黑色。它将是您在使用Markus提到的外观代理时设置的任何颜色。黑色设置是导航栏的样式很棒,这应该是他接受了答案——答案很简单,没有副作用,也没有使用私人方法。将
条样式设置为
。黑色
也会影响嵌入式搜索栏。因此搜索栏的背景是黑色的。几乎可以肯定,当你使用
UISearchController
@fivewood时,这不是你想要的。哪个部分不起作用rt 1或第2部分?条件为true,if语句的主体似乎已执行,但我的提示文本没有更改。iOS的哪个版本?这个答案适用于iOS 11。我很好奇iOS 12中的私有API(SPI)或内部类名是否发生了更改。这是我第一次看到它
- (void)layoutSubviews {
    [super layoutSubviews];

    if (self.topItem.prompt) {
        UILabel *promptLabel = [[self recursiveSubviewsOfKind:UILabel.class] selectFirstObjectUsingBlock:^BOOL(UILabel *label) {
            return [label.text isEqualToString:self.topItem.prompt];
        }];
        promptLabel.textColor = self.tintColor;
    }
}
import UIKit
class ViewController: UITableViewController {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        updatePrompt()
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        updatePrompt()
    }
    func updatePrompt() {
        navigationItem.prompt = " "
        for view in navigationController?.navigationBar.subviews ?? [] where NSStringFromClass(view.classForCoder) == "_UINavigationBarModernPromptView" {
            if let prompt = view.subviews.first as? UILabel {
                prompt.text = "Hello Red Prompt"
                prompt.textColor = .red
            }
        }
        navigationItem.title = "This is the title (Another color)"
    }
}