ナビゲーションバーのプロンプトの色を変更できません。以下のコードをviewDidLoad
で試しましたが、何も起こりません。
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
私は何かが足りないのですか?上記のコードは間違っていますか?
あなたはこれについて正しいようです。 iOS 11でプロンプトテキストのスタイルを設定するには、UIAppearance
を使用する必要があります。
IOS 11のプロンプトでtitleTextAttributes
プロパティが機能しなくなったというレーダー#34758558を提出しました。
良いニュースは、Xcodeのビュー階層デバッガーを使用して明らかにできるいくつかの回避策があることです。
// 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に応答する可能性のある独自のクラスがあります...
// 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つのソリューションのいずれかで得られるものを確認してください。
IOS 11でプロンプトの色を白にすることができました。barStyleを黒に設定していました。外観プロキシを使用して、他の色属性(目的の背景色など)を設定します。
myNavbar.barStyle = UIBarStyleBlack; // Objective-C
myNavbar.barStyle = .black // Swift
あなたは使用することができます
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()
}
}
カスタムの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:
を実装することは、読者の練習問題として残されていますか????。
これを試してみてください:->
navController.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.red]
IOS11の次の回避策を見つけました。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()
}
}
あなたはこれを試すことができます:
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)"
}
}
Mosheの最初の回答は、メールやテキスト作成VCなどのシステムVC内のラベルを変更したため、うまくいきませんでした。これらのナビゲーションバーの背景を変更することはできますが、それによって他のすべてのワームの缶が開かれます。プライベートクラスのルートに行きたくなかったので、カスタムナビゲーションバーサブクラス内に含まれているUILabelsのみを変更しました。
UILabel.appearance(whenContainedInInstancesOf: [NavigationBar.self]).textColor = UIColor.white