Can't change UINavigationBar prompt color

2020-03-01 05:47发布

I am unable to change the prompt color on my navigation bar. I've tried the code below in viewDidLoad, but nothing happens.

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

navigation bar image

Am I missing something? Is the code above wrong?

9条回答
趁早两清
2楼-- · 2020-03-01 05:48

I suggest using a custom UINavigationBar subclass and overriding 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;
    }
}

Basically I'm enumerating all UILabels in the subview hierarchy and check if their text matches the prompt text. Then we set the textColor to the tintColor (feel free to use a custom color). That way, we don't have to hardcode the private _UINavigationBarModernPromptView class as the prompt label's superview. So the code is be a bit more future-proof.

Converting the code to Swift and implementing the helper methods recursiveSubviewsOfKind: and selectFirstObjectUsingBlock: are left as an exercise to the reader

查看更多
ゆ 、 Hurt°
3楼-- · 2020-03-01 05:49

I've found next work around for iOS 11. You need set at viewDidLoad navigationItem.prompt = UINavigationController.fakeUniqueText and after that put next thing

    navigationController?.promptLabel(completion: { label in
    label?.textColor = .white
    label?.font = Font.regularFont(size: .p12)
        })

    extension UINavigationController {
    public static let fakeUniqueText = "\n\n\n\n\n"
    func promptLabel(completion: @escaping (UILabel?) -> Void) {
        gloabalThread(after: 0.5) { [weak self] in
            guard let `self` = self else {
                return
            }
            let label = self.findPromptLabel(at: self.navigationBar)
            mainThread {
                completion(label)
            }
        }
    }

    func findPromptLabel(at view: UIView) -> UILabel? {
        if let label = view as? UILabel {
            if label.text == UINavigationController.fakeUniqueText {
                return label
            }
        }
        var label: UILabel?
        view.subviews.forEach { subview in
            if let promptLabel = findPromptLabel(at: subview) {
                label = promptLabel
            }
        }
        return label
    }
    }


    public func mainThread(_ completion: @escaping SimpleCompletion) {
        DispatchQueue.main.async(execute: completion)
    }


    public func gloabalThread(after: Double, completion: @escaping SimpleCompletion) {
       DispatchQueue.global().asyncAfter(deadline: .now() + after) {
       completion()
    }
}

查看更多
ゆ 、 Hurt°
4楼-- · 2020-03-01 05:51

I was able to make the prompt color white on iOS 11 was setting the barStyle to black. I set the other color attributes (like the desired background color) using the appearance proxy:

myNavbar.barStyle = UIBarStyleBlack; // Objective-C
myNavbar.barStyle = .black // Swift
查看更多
姐就是有狂的资本
5楼-- · 2020-03-01 06:01

More complicated version to support old and new 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()
    }
}
查看更多
Viruses.
6楼-- · 2020-03-01 06:04

Try this out:->

navController.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.red]
查看更多
别忘想泡老子
7楼-- · 2020-03-01 06:06

You may use

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

It will be a temporary workaround until they'll fix it

查看更多
登录 后发表回答