UINavigationBar tint color does not update - ios

I am implementing a dark mode in my app. Here is my code (that I call when the screen is double tapped):
if darkMode == false {
UINavigationBar.appearance().tintColor = UIColor(hexString: "#3A3A3A")
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent
} else {
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.Default
UINavigationBar.appearance().barTintColor = UIColor(hexString: "#FFFDF3")
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.blackColor()]
The only thing that updates is my status bar, but the navigation bar does update after I go into another view and return back to the main view. Why is that? Is there something I'm doing wrong?

I was just dealing with the same issue, turns out if you change appearance() proxy at runtime it doesn't have any effect. You need to change directly the properties of instances. So what you need to do is have subclassed UINavigationBarController with method where you set the colors and status bar appearance, for instance:
class ColorNavigationController: UINavigationController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
setupForColor(UIFactory.sharedInstance.tintColor) //provides default color
}
func setupForColor(color: UIColor) {
navigationBar.tintColor = color
navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent
}
}
Then when you double tap the screen:
if let colorNavigationController = self.navigationController as? ColorNavigationController {
colorNavigationController.setupForColor(UIColor.redColor) // based on your current scheme
}

Got it. You can't change appearance() at runtime, but you can just do navigationController?.navigationBar.tintColor = UIColor.redColor()

Related

Unable to change navigation bar color during runtime via code?

I tested against iOS 14.5
We would like to provide ability to change the navigation bar color during runtime.
However, I notice the following code no longer has any effect.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
navigationController?.navigationBar.backgroundColor = UIColor.red
navigationController?.navigationBar.tintColor = UIColor.red
UINavigationBar.appearance().barTintColor = UIColor.red
}
}
But, if I did it directly in Storyboard, it works just fine.
We would like to have ability to change the various different color during runtime (via user button clicked)
Does anyone has any idea why the above code broken?
Thanks.
p/s I can confirm the navigationController is not nil.
On iOS 13 & above, you have to use new UINavigationBarAppearance api to get the correct color.
public extension UINavigationBar {
func applyPlainAppearanceFix(barTintColor: UIColor, tintColor: UIColor) {
if #available(iOS 13, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = barTintColor
self.standardAppearance = appearance
self.compactAppearance = appearance
self.scrollEdgeAppearance = appearance
}
self.isTranslucent = false
self.barTintColor = barTintColor
self.backgroundColor = barTintColor
self.tintColor = tintColor
}
}
From the call site it should look like
navigationController?.navigationBar.applyPlainAppearanceFix(barTintColor: .red, tintColor: .white)
Could you try adding this in your AppDelegate and I think it will work, if you didn't want it for all the app then your code is working fine, I've used it and it's working like in the image below:

How can I reload views after choose dark mode?

Im using this pod for add dark mode to my app.
https://github.com/draveness/NightNight
Its working well when I restart app again but I want to change theme inside of app. So, I added UISwitch to my sidepanel for user can change theme.
I added this codes for it and some colors changing well but some colors does not affect. For example NavigationBar background color is changing well but title color is not changing.
UISwitch Action:
#IBAction func switchMode(_ sender: UISwitch) {
if sender.isOn {
switcher.isOn = true
NightNight.theme = NightNight.Theme.night
UITabBar.appearance().barTintColor = UIColor(hexString: "#141d27")
UITabBar.appearance().isTranslucent = true
UITabBar.appearance().tintColor = UIColor(hexString: "#6e00ff")
UINavigationBar.appearance().tintColor = UIColor(hexString: "#6e00ff")
UINavigationBar.appearance().isTranslucent = true
UINavigationBar.appearance().barTintColor = UIColor(hexString: "#141d27")
for window in UIApplication.shared.windows {
for view in window.subviews {
view.removeFromSuperview()
window.addSubview(view)
}
}
UserDefaults.standard.set("night", forKey: "colormode")
} else {
switcher.isOn = false
NightNight.theme = NightNight.Theme.normal
UITabBar.appearance().barTintColor = UIColor.white
UITabBar.appearance().isTranslucent = true
UITabBar.appearance().tintColor = UIColor(hexString: "#6e00ff")
UINavigationBar.appearance().tintColor = UIColor(hexString: "#6e00ff")
UINavigationBar.appearance().isTranslucent = true
UINavigationBar.appearance().barTintColor = UIColor.white
for window in UIApplication.shared.windows {
for view in window.subviews {
view.removeFromSuperview()
window.addSubview(view)
}
}
UserDefaults.standard.set("normal", forKey: "colormode")
}
}
Normally gray text colors(User`s names and navigation title) must to be black in light mode, but they does not changed.
Use callback when view mode changes.
Change your colors as expected.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
// do whatever you want to do
}
Check out RxSwift and RxCocoa. They can both be found here. They are Reactive Frameworks for Reactive Programming in Swift. You can create observables to change the color of views reactively, as needed.

iOS black line on navigation controller transition

When the push/pop transition is performed on my view controller(which has large title and search bar embedded in navigation item), the black line appears briefly, like this:
I've basically tried changing all the navigation bar colour related things, but nothing helped.
Any help would be appreciated :)
extension UINavigationBar {
var customStyle: NavigationBarCustomStyle {
set(style) {
switch style {
case .clear:
self.setBackgroundImage(UIImage(), for: .default)
self.shadowImage = UIImage()
self.tintColor = .white
self.isTranslucent = false
break
case .bottomLine:
self.tintColor = .gray
self.backgroundColor = .yellow
self.isTranslucent = false
break
}
}
get {
return self.customStyle
}
}
}
enum NavigationBarCustomStyle {
case clear
case bottomLine
// case white
}
at ViewController >> viewDidLoad method put below line:
self.navigationController?.navigationBar.customStyle = .clear
Try set navbar's background color to white (depend on your case) fix the problem for me, though there still another glitch but its better :)
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.view.backgroundColor = .white
}

How to change UIDocumentInteractionController Done button text and background color

How to change the background color and text color of done button? Is there a way that I can change the navigationbar color and navigation bar title color and bottom bar color also? Attached screenshot for reference:
I solved it. Here is the code working for me perfectly:
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
UINavigationBar.appearance().barTintColor = Colors.redColor()
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white, NSFontAttributeName: UIFont.systemFont(ofSize: 14, weight: UIFontWeightBold)]
return self
}
It's a little hacky as its relying on the fact that QLPreviewController is the class implementing the UIDocumentInteractionController but something like this is the least intrusive solution. Do it before you display the UIDocumentInteractionController
import QuickLook
UIBarButtonItem.appearance(whenContainedInInstancesOf [QLPreviewController.self]).tintColor = UIColor.black
I have a idear to change the bar color:
let allNavigationBar = UINavigationBar.appearance()
allNavigationBar.barTintColor = UIColor.red // change the bar background color
allNavigationBar.tintColor = UIColor.black // change the Done button's tintColor
let alloolbar = UIToolbar.appearance()
allToolbar.barTintColor = UIColor.red // dones't work, try backgroundImage
allToolbar.backgroundColor = UIColor.blue // dones't work
allToolbar.tintColor = UIColor.brown // change the toolbar's item tint color
but this method has a great effect,all your UINavigationBarand UIToolBar will make that change.
Hope anyone else can give a better solusion.
You can change the tint color of the window temporally.
func presentDocument() {
//present the controller here
self.appDelegate.window.tintColor = UIColor.red
}
Then change it back later:
func documentInteractionControllerDidEndPreview(documentInteractionController) { //replace parameter with your uidocumentviewinteractioncontroller
self.appDelegate.window.tintColor = UIColor.white
}
#Dee. I guess you have asked this part in one of your other question. In that case you were not able to show that preview controller. In that question suggested answer is to return "self" from that delegate method. If you implement that correctly then your preview will use same navigation bar colour as its parent controller is using. I mean if you have opened UIDocumentInteractionController directly from some ViewController then UIDocumentInteractionController will use its parent viewController's navigation bar colour. This may help you to change Done button colour
Try this : (You need to implement UIDocumentInteractionControllerDelegate)
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self.navigationController ?? self
}
let QLNavAppearance = UINavigationBar.appearance(whenContainedInInstancesOf: [QLPreviewController.self])
QLNavAppearance.tintColor = UIColor.red // some
QLNavAppearance.barTintColor = UIColor.red // some
QLNavAppearance.backgroundColor = UIColor.red // some

How to definitively set UITabBar background color and tint color

I have been trying to set my UITabBar's tint color and background color for quite some time now and nothing seems to work.
So far I have tried:
tabBarController?.tabBar.backgroundColor = UIColor.orangeColor()
tabBarController?.tabBar.barTintColor = UIColor.whiteColor()
as well as:
UITabBar.appearance().tintColor = UIColor.orangeColor()
Neither of these seemed to have any effect on my tab bar. I'd also like to mention that I have the VC embedded in a navigation controller for which the global tint color that I set works perfectly fine.
If you want to set tabbar's tint and barTint color implicitly then in your Appdelegate.swift,
UITabBar.appearance().barTintColor = .orange
UITabBar.appearance().tintColor = .green
If you want to set tabbar's tint and barTint color for specific viewController then in ViewController.swift,
self.tabBarController?.tabBar.tintColor = .orange
self.tabBarController?.tabBar.barTintColor = .green
Set tab bar background color with barTintColor:
self.tabBar.barTintColor = UIColor.blueColor()
//or
UITabBar.appearance().barTintColor = UIColor.blueColor()
And for tab bar tint color:
self.tabBar.tintColor = UIColor.whiteColor() // Selected tab color
//or
UITabBar.appearance().tintColor = UIColor.whiteColor()
In similar fashion to how UINavigationBar is by default transparent on iOS 15 when there is no content behind it, the UITabBar works the same way. This might either be a nice visual refresh you get for free (since it is turned on by default once you build with Xcode 13) or it might cause a lot of issues for your app.
if #available(iOS 13.0, *) {
let tabBarAppearance: UITabBarAppearance = UITabBarAppearance()
tabBarAppearance.configureWithDefaultBackground()
tabBarAppearance.backgroundColor = UIColor.tabBarBackground
UITabBar.appearance().standardAppearance = tabBarAppearance
}
if #available(iOS 15.0, *) {
UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance
}
Also you can set it from UIEditor like so
I always like to do some kinds of settings on the storyboard. Here is the #IBDesignable extension
#IBDesignable extension UITabBar {
#IBInspectable var barTintColor: UIColor? {
set {
guard let uiColor = newValue else { return }
UITabBar.appearance().barTintColor = uiColor
}
get {
guard let color = UITabBar.appearance().barTintColor else { return nil }
return color
}
}}
Swift 4+ version
UITabBar.appearance().barTintColor = UIColor.red
UITabBar.appearance().tintColor = UIColor.white

Resources