Невозможно изменить цвет подсказки UINavigationBar
Я не могу изменить цвет приглашения на панели навигации. Я пробовал код ниже в viewDidLoad
, но ничего не происходит.
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
![изображение на навигационной панели]()
Я что-то упустил? Является ли код неправильным?
Ответы
Ответ 1
Кажется, вы правы в этом. Для стилизации текста приглашения на iOS 11 вам нужно использовать UIAppearance
.
Я подал радар # 34758558, что свойство titleTextAttributes
просто перестало работать для приглашения в iOS 11.
Хорошей новостью является то, что есть несколько способов обхода, которые мы можем выявить с помощью отладчика иерархии представлений Xcode:
![Снимок экрана с подсказкой строки UINavigation на iOS 11]()
// 1. This works, but potentially changes *all* labels in the navigation bar.
// If you want this, it works.
UILabel.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).textColor = UIColor.white
Приглашение - это всего лишь UILabel. Если мы используем UIAppearance whenContainedInInstancesOf:
, мы можем довольно легко обновить цвет так, как хотим.
Если вы внимательно присмотритесь, вы заметите, что в UILabel также есть оболочка. У этого есть свой класс, который мог бы ответить на UIAppearance...
![Снимок экрана с закрытым подзапросом UINavigationBar]()
// 2. This is a more precise workaround but it requires using a private class.
if let promptClass = NSClassFromString("_UINavigationBarModernPromptView") as? UIAppearanceContainer.Type
{
UILabel.appearance(whenContainedInInstancesOf: [promptClass]).textColor = UIColor.white
}
Я бы посоветовал придерживаться более общего решения, поскольку он не использует частный API. (Обзор приложений и т.д.) Проверьте, что вы получаете с любым из этих двух решений:
![Правильно окрашенный текст подсказки]()
Ответ 2
Мне удалось сделать приглашение цвета white на iOS 11, чтобы barStyle был черным. Я установил другие цветовые атрибуты (например, желаемый цвет фона) с помощью прокси-сервера вида:
myNavbar.barStyle = UIBarStyleBlack; // Objective-C
myNavbar.barStyle = .black // Swift
Ответ 3
Вы можете использовать
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
}
}
Это будет временный обходной путь, пока они не исправят это
Ответ 4
Более сложная версия для поддержки старой и новой 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()
}
}
Ответ 5
Попробуйте это: →
navController.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.red]
Ответ 6
Первый ответ моше не сработал для меня, потому что он изменил метки внутри системных ВК, такие как почта и текст, составляют ВК. Я мог бы изменить фон этих навигационных панелей, но это открывает еще одну банку с червями. Я не хотел идти по пути частного класса, поэтому я изменил только UILabels, содержащиеся в моем подклассе пользовательской панели навигации.
UILabel.appearance(whenContainedInInstancesOf: [NavigationBar.self]).textColor = UIColor.white
Ответ 7
Я нашел следующую работу вокруг iOS 11.
Вам нужно установить на viewDidLoad
navigationItem.prompt = UINavigationController.fakeUniqueText
и после этого поставьте следующую вещь
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()
}
}
Ответ 8
Я предлагаю использовать пользовательский подкласс 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 (не стесняйтесь использовать пользовательский цвет). Таким образом, нам не нужно жестко кодировать закрытый класс _UINavigationBarModernPromptView
в качестве суперпредставления метки приглашения. Таким образом, код будет более перспективным.
Преобразование кода в Swift и реализация вспомогательных методов recursiveSubviewsOfKind:
и selectFirstObjectUsingBlock:
оставлены читателю в качестве упражнения 😉.
Ответ 9
Вы можете попробовать это:
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)"
}
}
![Screenshot]()