SwiftUI update navigation bar title color
IosNavigationbarSwiftuiIos Problem Overview
How to change the navigation bar title color in SwiftUI
NavigationView {
List{
ForEach(0..<15) { item in
HStack {
Text("Apple")
.font(.headline)
.fontWeight(.medium)
.color(.orange)
.lineLimit(1)
.multilineTextAlignment(.center)
.padding(.leading)
.frame(width: 125, height: nil)
Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
.font(.subheadline)
.fontWeight(.regular)
.multilineTextAlignment(.leading)
.lineLimit(nil)
}
}
}
.navigationBarTitle(Text("TEST")).navigationBarHidden(false).foregroundColor(.orange)
}
I have tried with .foregroundColor(.orange)
but it is not working
also tried .navigationBarTitle(Text("TEST").color(.orange))
Any help ?
Ios Solutions
Solution 1 - Ios
It is not necessary to use .appearance()
to do this globally.
Although SwiftUI does not expose navigation styling directly, you can work around that by using UIViewControllerRepresentable
. Since SwiftUI is using a regular UINavigationController
behind the scenes, the view controller will still have a valid .navigationController
property.
struct NavigationConfigurator: UIViewControllerRepresentable {
var configure: (UINavigationController) -> Void = { _ in }
func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationConfigurator>) -> UIViewController {
UIViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationConfigurator>) {
if let nc = uiViewController.navigationController {
self.configure(nc)
}
}
}
And to use it
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
Text("Don't use .appearance()!")
}
.navigationBarTitle("Try it!", displayMode: .inline)
.background(NavigationConfigurator { nc in
nc.navigationBar.barTintColor = .blue
nc.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.white]
})
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
Solution 2 - Ios
In SwiftUI, you can not change the navigationTitleColor directly. You have to change UINavigation's appearance in init()
like this,
struct YourView: View {
init() {
//Use this if NavigationBarTitle is with Large Font
UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: UIColor.red]
//Use this if NavigationBarTitle is with displayMode = .inline
UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.red]
}
var body: some View {
NavigationView {
List{
ForEach(0..<15) { item in
HStack {
Text("Apple")
.font(.headline)
.fontWeight(.medium)
.color(.orange)
.lineLimit(1)
.multilineTextAlignment(.center)
.padding(.leading)
.frame(width: 125, height: nil)
Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
.font(.subheadline)
.fontWeight(.regular)
.multilineTextAlignment(.leading)
.lineLimit(nil)
}
}
}
.navigationBarTitle(Text("TEST")).navigationBarHidden(false)
//.navigationBarTitle (Text("TEST"), displayMode: .inline)
}
}
}
I hope it will work. Thanks!!
Solution 3 - Ios
I have searched for this issue and find a great article about this, you could wrap the settings of navigation bar style as a view modifier.
Check this Link.
Notes: I believe you need to update some code in this example, add titleColor
parameter.
struct NavigationBarModifier: ViewModifier {
var backgroundColor: UIColor?
var titleColor: UIColor?
init(backgroundColor: UIColor?, titleColor: UIColor?) {
self.backgroundColor = backgroundColor
let coloredAppearance = UINavigationBarAppearance()
coloredAppearance.configureWithTransparentBackground()
coloredAppearance.backgroundColor = backgroundColor
coloredAppearance.titleTextAttributes = [.foregroundColor: titleColor ?? .white]
coloredAppearance.largeTitleTextAttributes = [.foregroundColor: titleColor ?? .white]
UINavigationBar.appearance().standardAppearance = coloredAppearance
UINavigationBar.appearance().compactAppearance = coloredAppearance
UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
}
func body(content: Content) -> some View {
ZStack{
content
VStack {
GeometryReader { geometry in
Color(self.backgroundColor ?? .clear)
.frame(height: geometry.safeAreaInsets.top)
.edgesIgnoringSafeArea(.top)
Spacer()
}
}
}
}
}
extension View {
func navigationBarColor(backgroundColor: UIColor?, titleColor: UIColor?) -> some View {
self.modifier(NavigationBarModifier(backgroundColor: backgroundColor, titleColor: titleColor))
}
}
After that, apply like this:
.navigationBarColor(backgroundColor: .clear, titleColor: .white)
I hope it will work.
Solution 4 - Ios
In iOS 14, SwiftUI has a way to customize a navigation bar with the new toolbar
modifier.
We need to set ToolbarItem
of placement type .principal
to a new toolbar
modifier. You can even set an image and much more.
NavigationView {
Text("My View!")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
HStack {
Image(systemName: "sun.min.fill")
Text("Title")
.font(.headline)
.foregroundColor(.orange)
}
}
}
}
Solution 5 - Ios
Building on the answer from Arsenius, I found that an elegant way to get it to work consistently was to subclass UIViewController
and do the configuration in viewDidLayoutSubviews()
.
Usage:
VStack {
Text("Hello world")
.configureNavigationBar {
$0.navigationBar.setBackgroundImage(UIImage(), for: .default)
$0.navigationBar.shadowImage = UIImage()
}
}
Implementation:
extension View {
func configureNavigationBar(configure: @escaping (UINavigationController) -> Void) -> some View {
modifier(NavigationConfigurationViewModifier(configure: configure))
}
}
struct NavigationConfigurationViewModifier: ViewModifier {
let configure: (UINavigationController) -> Void
func body(content: Content) -> some View {
content.background(NavigationConfigurator(configure: configure))
}
}
struct NavigationConfigurator: UIViewControllerRepresentable {
let configure: (UINavigationController) -> Void
func makeUIViewController(
context: UIViewControllerRepresentableContext<NavigationConfigurator>
) -> NavigationConfigurationViewController {
NavigationConfigurationViewController(configure: configure)
}
func updateUIViewController(
_ uiViewController: NavigationConfigurationViewController,
context: UIViewControllerRepresentableContext<NavigationConfigurator>
) { }
}
final class NavigationConfigurationViewController: UIViewController {
let configure: (UINavigationController) -> Void
init(configure: @escaping (UINavigationController) -> Void) {
self.configure = configure
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let navigationController = navigationController {
configure(navigationController)
}
}
}
Solution 6 - Ios
I took a slightly different approach; I wanted to change only the title text color, and nothing else about the NavigationBar
. Using the above and this as inspiration, I landed on:
import SwiftUI
extension View {
/// Sets the text color for a navigation bar title.
/// - Parameter color: Color the title should be
///
/// Supports both regular and large titles.
@available(iOS 14, *)
func navigationBarTitleTextColor(_ color: Color) -> some View {
let uiColor = UIColor(color)
// Set appearance for both normal and large sizes.
UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: uiColor ]
UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: uiColor ]
return self
}
}
This requires iOS 14 because UIColor.init(_ color: Color)
requires iOS 14.
Which can be leveraged as such:
struct ExampleView: View {
var body: some View {
NavigationView {
Text("Hello, World!")
.navigationBarTitle("Example")
.navigationBarTitleTextColor(Color.red)
}
}
}
Which in turn yields:
Solution 7 - Ios
I have developed a small sample of a custom SwiftUI navigation that can provide full visual customisation and programatic navigation. It can be used as a replacement for the NavigationView.
Here is the NavigationStack class that deals with currentView and navigation stack:
final class NavigationStack: ObservableObject {
@Published var viewStack: [NavigationItem] = []
@Published var currentView: NavigationItem
init(_ currentView: NavigationItem ){
self.currentView = currentView
}
func unwind(){
if viewStack.count == 0{
return
}
let last = viewStack.count - 1
currentView = viewStack[last]
viewStack.remove(at: last)
}
func advance(_ view:NavigationItem){
viewStack.append( currentView)
currentView = view
}
func home( ){
currentView = NavigationItem( view: AnyView(HomeView()))
viewStack.removeAll()
}
}
You can have a look here: for the full example with explanation:
PS: I am not sure why this one was deleted. I think it answer the question as it is a perfect functional alternative to NavigationView.
Solution 8 - Ios
Use Below Code for Color Customization in SwiftUI
This is for main body background color:-
struct ContentView: View {
var body: some View {
Color.red
.edgesIgnoringSafeArea(.all)
}
}
For Navigation Bar:-
struct ContentView: View {
@State var msg = "Hello SwiftUI😊"
init() {
UINavigationBar.appearance().backgroundColor = .systemPink
UINavigationBar.appearance().largeTitleTextAttributes = [
.foregroundColor: UIColor.white,
.font : UIFont(name:"Helvetica Neue", size: 40)!]
}
var body: some View {
NavigationView {
Text(msg)
.navigationBarTitle(Text("NAVIGATION BAR"))
}
}
}
For Other UI Elements Color Customization
struct ContentView: View {
@State var msg = "Hello SwiftUI😊"
var body: some View {
Text(msg).padding()
.foregroundColor(.white)
.background(Color.pink)
}
}
Solution 9 - Ios
init() {
// for navigation bar title color
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.red]
// For navigation bar background color
UINavigationBar.appearance().backgroundColor = .green
}
NavigationView {
List {
ForEach(0..<15) { item in
HStack {
Text("Apple")
.font(.headline)
.fontWeight(.medium)
.color(.orange)
.lineLimit(1)
.multilineTextAlignment(.center)
.padding(.leading)
.frame(width: 125, height: nil)
Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
.font(.subheadline)
.fontWeight(.regular)
.multilineTextAlignment(.leading)
.lineLimit(nil)
}
}
}
.navigationBarTitle(Text("TEST")).navigationBarHidden(false)
}
Solution 10 - Ios
If you have your content as
struct MyContent : View {
...
}
then you can put it like this inside a navigation view with a red background:
NavigationView {
ZStack(alignment: .top) {
Rectangle()
.foregroundColor(Color.red)
.edgesIgnoringSafeArea(.top)
MyContent()
}
}
I will update my answer as soon as I know how to update the title text itself.
Solution 11 - Ios
Instead of setting appearance()
, which affects all navigation bars, you can set them individually using SwiftUI-Introspect.
Example:
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
Text("Hello world!")
}
.navigationTitle("Title")
}
.introspectNavigationController { nav in
nav.navigationBar.barTintColor = .systemBlue
}
}
}
Result:
Solution 12 - Ios
Definitely there are already a few good answers, but all of them will cover only part of the job:
-
Great solution from @arsenius - give the good point to start
-
Elegant way from @EngageTheWarpDrive - this definitely improve usability
-
For latest version of iOS and swiftUI @Thahir suggest to use toolbar
Few more suggestions propose to use UIAppearence
global config for UINavigationBar
- as for me global change is not a good idea and may be not always suitable.
I ended up combining all proposals in to the next code:
-
Create
NavigationControllerRepresentable
andmodifier
fornavigationBar
configuration:struct NavigationControllerLayout: UIViewControllerRepresentable { var configure: (UINavigationController) -> () = { _ in } func makeUIViewController( context: UIViewControllerRepresentableContext<NavigationControllerLayout> ) -> UIViewController { UIViewController() } func updateUIViewController( _ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationControllerLayout> ) { if let navigationContoller = uiViewController.navigationController { configure(navigationContoller) } } } extension View { func configureNavigationBar(_ configure: @escaping (UINavigationBar) -> ()) -> some View { modifier(NavigationConfigurationViewModifier(configure: configure)) } } struct NavigationConfigurationViewModifier: ViewModifier { let configure: (UINavigationBar) -> () func body(content: Content) -> some View { content.background(NavigationControllerLayout(configure: { configure($0.navigationBar) })) } }
-
To modify
navigationBar
to meet u'r requirements (such as bg color and other props):extension UINavigationBar { enum Appearence { case transparent case defaultLight case colored(UIColor?) var color: UIColor { ... } var appearenceColor: UIColor { ... } var tint: UIColor { .... } var effect: UIBlurEffect? { .... } } func switchToAppearence(_ type: Appearence) { backgroundColor = type.color barTintColor = type.tint // for iOS 13+ standardAppearance.backgroundColor = type.appearenceColor standardAppearance.backgroundEffect = type.effect // u can use other properties from navBar also simply modifying this function } }
-
As u can see, here we definitely need some bridge between
Color
andUIColor
. Starting fromiOS 14
- u can justUIColor.init(_ color: Color)
, but beforeiOS 14
there is not such way, so I ended up with simple solution:extension Color { /// Returns a `UIColor` that represents this color if one can be constructed /// /// Note: Does not support dynamic colors var uiColor: UIColor? { self.cgColor.map({ UIColor(cgColor: $0) }) } }
> this will not work for dynamic colors
-
As result u can use this as following:
// modifier to `NavigationView` .configureNavigationBar { $0.switchToAppearence(.defaultLight) }
Hopefully this may help to someone ;)
Solution 13 - Ios
I still haven't figured out how to do the foreground color on a per-view basis, but I did figure out a simple workaround for the background color.
If using an .inline
title, you can just use a VStack
with a rectangle at the top of the NavigationView
:
NavigationView {
VStack() {
Rectangle()
.foregroundColor(.red)
.edgesIgnoringSafeArea(.top)
.frame(height: 0)
List {
Text("Hello World")
Text("Hello World")
Text("Hello World")
}
}
.navigationBarTitle("Hello World", displayMode: .inline)
// ...
Note how the rectangle uses a frame height of 0
and .edgesIgnoringSafeArea(.top)
.
Solution 14 - Ios
Here is the solution that worked for me. You need to start off with a UINavigationController as the rootViewController.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let nav = setupNavigationController()
window.rootViewController = nav
self.window = window
window.makeKeyAndVisible()
}
}
func setupNavigationController() -> UINavigationController {
let contentView = ContentView()
let hosting = UIHostingController(rootView: contentView)
let nav = NavigationController(rootViewController: hosting)
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
navBarAppearance.backgroundColor = UIColor.black
nav.navigationBar.standardAppearance = navBarAppearance
nav.navigationBar.scrollEdgeAppearance = navBarAppearance
nav.navigationBar.prefersLargeTitles = true
return nav
}
and then in your content view:
struct ContentView: View {
@State private var isModalViewPresented: Bool = false
var body: some View {
List(0 ..< 10, rowContent: { (index) in
NavigationLink(destination: DetailView()) {
Text("\(index)")
}
})
.navigationBarItems(trailing: Button("Model") {
self.isModalViewPresented.toggle()
})
.sheet(isPresented: $isModalViewPresented, content: {
ModalView()
})
.navigationBarTitle("Main View")
}
}
and if you want to change the color at some point, such as in a modal view, use the answer given here
struct ModalView: View {
var body: some View {
NavigationView {
Text("Hello, World!")
.navigationBarTitle("Modal View")
.background(NavigationConfigurator { nc in
nc.navigationBar.backgroundColor = UIColor.blue
nc.navigationBar.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
})
}
}
}
you can subclass UINavigationController to change the status bar color
class NavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
}
override var preferredStatusBarStyle: UIStatusBarStyle
{
.lightContent
}
}
Solution 15 - Ios
.foregroundColor(.orange)
- изменяет внутренние представления NavigationView.
But to change the navigation view itself, you need to use UINavigationBar Appearance()
in init()
I was looking for this problem and found a great article about it. And i modified your code by this article and came to success. Here, how i solve this problem:
struct ContentView: View {
init() {
let coloredAppearance = UINavigationBarAppearance()
// this overrides everything you have set up earlier.
coloredAppearance.configureWithTransparentBackground()
coloredAppearance.backgroundColor = .green
coloredAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.black]
// to make everything work normally
UINavigationBar.appearance().standardAppearance = coloredAppearance
UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
}
var body: some View {
NavigationView {
List{
ForEach(0..<15) { item in
HStack {
Text("Apple")
.font(.headline)
.fontWeight(.medium)
.lineLimit(1)
.multilineTextAlignment(.center)
.padding(.leading)
.frame(width: 125, height: nil)
.foregroundColor(.orange)
Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
.font(.subheadline)
.fontWeight(.regular)
.multilineTextAlignment(.leading)
.lineLimit(nil)
.foregroundColor(.orange)
}
}
}
.navigationBarTitle(Text("TEST"))
}
// do not forget to add this
.navigationViewStyle(StackNavigationViewStyle())
}
}
You can also take some examples here
Solution 16 - Ios
update for 13.4
note: revisiting this the next day, it may be possible that some of my issues were caused by my somewhat nonstandard setup: i am still running mojave, but have manually added the 13.4 support files (normally available only via xcode 11.4, which requires catalina). i mention this because i am/was also having some tab bar custom color issues, but i just noticed that those are only manifesting when i have the phone actually plugged in and am running the app from xcode. if i unplug, and just run the app normally, i am not seeing the tab bar issues, so it may be possible that the nav bar issue had some similarity ...
(i would add this as a comment on arsenius' answer (the currently accepted one) above, but i don't have the rep, so ...)
i was using that solution, and it was working perfectly up until 13.4, which seems to have broken it, at least for me. after a lot of view hierarchy tracing, it looks like they changed things such that the implicit UINavigationController is no longer easily accessible via the passed UIViewController as described in the workaround. it's still there though (pretty far up the tree), we just have to find it.
to that end, we can just walk the view hierarchy until we find the navbar, and then set the desired parameters on it, as usual. this necessitates a new discovery function, and some minor changes to the NavigationConfigurator struct, and its instantiation ...
first up, the discovery function:
func find_navbar(_ root: UIView?) -> UINavigationBar?
{
guard root != nil else { return nil }
var navbar: UINavigationBar? = nil
for v in root!.subviews
{ if type(of: v) == UINavigationBar.self { navbar = (v as! UINavigationBar); break }
else { navbar = find_navbar(v); if navbar != nil { break } }
}
return navbar
}
modify the NavigationConfigurator as follows (note that we no longer care about passing in a view, since that's no longer reliable):
struct NavigationConfigurator: UIViewControllerRepresentable
{
@EnvironmentObject var prefs: Prefs // to pick up colorscheme changes
var configure: () -> Void = {}
func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationConfigurator>) -> UIViewController { UIViewController() }
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationConfigurator>) { self.configure() }
}
(in my app, i have a Prefs object which keeps track of colors, etc.)
... then, at the instantiation site, do something like this:
MyView()
.navigationBarTitle("List", displayMode: .inline)
.navigationBarItems(trailing: navbuttons)
.background(NavigationConfigurator {
if self.prefs.UI_COLORSCHEME != Colorscheme.system.rawValue
{ if let navbar = find_navbar(root_vc?.view)
{ navbar.barTintColor = Colors.uicolor(.navbar, .background)
navbar.backgroundColor = .black
navbar.titleTextAttributes = [.foregroundColor: Colors.uicolor(.navbar, .foreground)]
navbar.tintColor = Colors.uicolor(.navbar, .foreground)
}
}
})
note that i capture the root view controller elsewhere in my app, and use it here to pass to find_navbar(). you might want to do it differently, but i already have that variable around for other reasons ... there's some other stuff there specific to my app, e.g., the color-related objects, but you get the idea.
Solution 17 - Ios
https://stackoverflow.com/a/58427754/4709057 this answer works, but if you are experiencing issues with navigationController being nil in light or dark mode. Just add this.. no idea why it works.
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
Text("Don't use .appearance()!")
}
.navigationBarTitle("Try it!", displayMode: .inline)
.background(NavigationConfigurator { nc in
nc.navigationBar.barTintColor = .blue
nc.navigationBar.background = .blue
nc.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.white]
})
}
.navigationViewStyle(StackNavigationViewStyle())
.accentColor(.red) <------- DOES THE JOB
}
}
Solution 18 - Ios
WatchOS navigation title color using SwiftUI
Side note for watchOS is that you don't need to fiddle with the navigation color. It's the Watch Accent color you need to change. In your project go into WatchProjectName->Asset->Accent and change this
https://developer.apple.com/documentation/watchkit/setting_the_app_s_tint_color
Solution 19 - Ios
Based on this https://stackoverflow.com/a/66050825/6808357 I created an extension where you can set the background color and the title color at the same time.
import SwiftUI
extension View {
/// Sets background color and title color for UINavigationBar.
@available(iOS 14, *)
func navigationBar(backgroundColor: Color, titleColor: Color) -> some View {
let appearance = UINavigationBarAppearance()
appearance.configureWithTransparentBackground()
appearance.backgroundColor = UIColor(backgroundColor)
let uiTitleColor = UIColor(titleColor)
appearance.largeTitleTextAttributes = [.foregroundColor: uiTitleColor]
appearance.titleTextAttributes = [.foregroundColor: uiTitleColor]
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
return self
}
}
Here's how to use it:
var body: some View {
NavigationView {
Text("Hello world!") // This could be any View (List, VStack, etc.)
.navigationTitle("Your title here")
.navigationBar(backgroundColor: .blue, titleColor: .white)
}
}
Happy coding!
Solution 20 - Ios
The solution that worked for me was to use UINavigationBarAppearance() method, then add the .id() to the NavigationView. This will automatically redraw the component when the color changes.
Now you can have reactive color changes based on a state engine.
var body: some Scene {
let color = someValue ? UIColor.systemBlue : UIColor.systemGray3
let custom = UINavigationBarAppearance()
custom.configureWithOpaqueBackground()
custom.backgroundColor = color
UINavigationBar.appearance().standardAppearance = custom
UINavigationBar.appearance().scrollEdgeAppearance = custom
UINavigationBar.appearance().compactAppearance = custom
UINavigationBar.appearance().compactScrollEdgeAppearance = custom
return WindowGroup {
NavigationView {
content
}
.id(color.description)
}
}
Solution 21 - Ios
This solution builds on the accepted answer that doesn't use any library nor does it apply UINavigationBarAppearance
globally.
This solution fixes the issues that the accepted answer has (such as not working for the initial view or not working for large display mode) by adding a hack.
Note I would personally not use this hack in production code, nevertheless it's interesting to see that the issues can be worked around. Use at own risk.
struct NavigationHackView: View {
@State private var isUsingHack = false
var body: some View {
NavigationView {
List {
NavigationLink {
Text("Detail view")
.navigationTitle("Detail view")
.navigationBarTitleDisplayMode(.inline)
} label: {
Text("Show details view")
}
}
.navigationTitle("Hack!")
.background(
NavigationConfigurator { navigationController in
// required for hack to work
_ = isUsingHack
navigationController.navigationBar.navigationBarColor(.red, titleColor: .white)
}
)
.onAppear {
// required for hack to work
DispatchQueue.main.async {
isUsingHack.toggle()
}
}
// required for hack to work, even though nothing is done
.onChange(of: isUsingHack) { _ in }
}
}
}
struct NavigationConfigurator: UIViewControllerRepresentable {
var configure: (UINavigationController) -> Void = { _ in }
func makeUIViewController(
context: UIViewControllerRepresentableContext<NavigationConfigurator>
) -> UIViewController {
UIViewController()
}
func updateUIViewController(
_ uiViewController: UIViewController,
context: UIViewControllerRepresentableContext<NavigationConfigurator>
) {
guard let navigationController = uiViewController.navigationController else {
return
}
configure(navigationController)
}
}
extension UINavigationBar {
func navigationBarColor(
_ backgroundColor: UIColor,
titleColor: UIColor? = nil
) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = backgroundColor
if let titleColor = titleColor {
appearance.titleTextAttributes = [.foregroundColor: titleColor]
appearance.largeTitleTextAttributes = [.foregroundColor: titleColor]
// back button appearance
tintColor = titleColor
}
standardAppearance = appearance
scrollEdgeAppearance = appearance
compactAppearance = appearance
if #available(iOS 15.0, *) {
compactScrollEdgeAppearance = appearance
}
}
}
Solution 22 - Ios
Post iOS 14 easy way to do:
protocol CustomNavigationTitle: View {
associatedtype SomeView: View
func customNavigationTitle(_ string: String) -> Self.SomeView
}
extension CustomNavigationTitle {
func customNavigationTitle(_ string: String) -> some View {
toolbar {
ToolbarItem(placement: .principal) {
Text(string).foregroundColor(.red).font(.system(size: 18))
}
}
}
}
extension ZStack: CustomNavigationTitle {}
Suppose your root view of view is made with ZStack
it can be utilised below way
ZStack {
}. customNavigationTitle("Some title")
Solution 23 - Ios
The simplest way I found was:
init() {
UINavigationBar.appearance().tintColor = UIColor.systemBlue
}
instead of the systemBlue you can use any other colors that you wish. You have to implement this outside the "var body: some View {}". you can also add:
@Environment(/.colorScheme) var colorScheme
on top of the init()
and then you can use the .dark or .light to change the color the way you want in dark mode and light mode. example:
init() {
UINavigationBar.appearance().tintColor = UIColor(colorScheme == .dark ? .white : Color(#colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1)))
}