How to change color of ToolbarItem with navigationBarLeading placement in SwiftUI
Asked Answered
O

5

10

I need a title to be on the left side of a navigation bar. I use the following code:

.toolbar {
    ToolbarItem(placement: .navigationBarLeading) {
        Text("Title")
            .foregroundColor(.black)
    }
}

The problem is that it is displayed blue and as a button. Is it possible to change its color to black somehow? foregroundColor, accentColor do not work. Also, I tried to use a disabled button with Text("Title") inside. But it was displayed grey in that case. Not color, nor PlainButtonStyle were applied.

Omeromero answered 21/10, 2020 at 16:2 Comment(0)
C
21

By default if you add a single Text it's displayed as a Button.

Then, to change its color you need to set the accentColor of the NavigationView (as this button is displayed in the navigation bar):

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("Test")
                .toolbar {
                    ToolbarItem(placement: .navigationBarLeading) {
                        Text("Title")
                    }
                }
        }
        .accentColor(.black)
    }
}

If you don't want to change the accentColor in the whole NavigationView you can do:

NavigationView {
    VStack {
        //...
    }
    .accentColor(.accentColor)
}
.accentColor(.black)

However, if you want this Text to behave like a Text and not like a Button you can use the following hack:

ToolbarItem(placement: .navigationBarLeading) {
    HStack {
        Text("Title")
        Text("")
    }
    .foregroundColor(.red)
}
Connected answered 21/10, 2020 at 17:2 Comment(6)
this is an awesome solution - tried that, but didn't know it's only fixable by setting it to the NavigationView.But the text still automatically becomes a button. Only UIViewRepresentable keeps the Text as a TextHemophilia
@Lonkly This is just how the toolbar works if you add just a Text (in the current version of SwiftUI). If you add two Texts wrapped in a HStack it behaves differently.Connected
I am unable to get the VStack { // ... }.accentColor() to work to change the color of just one toolbar item. I am putting the VStack inside ToolbarItem(), around the Text(), like this: ToolbarItem(placement: .navigationBarTrailing) { VStack { Text("hi") }.accentColor(.red). Is this what you meant or am I doing it wrong?Shulamith
@Shulamith In the first solution it's the .accentColor(.black) on NavigationView which changes toolbar items color (not the .accentColor(.accentColor) on VStack). And it changes color for all toolbar items. If you want to change the specific item you need the 2nd solution (with HStack).Connected
Ah, thanks. It works for individual items now. In fact it works with both VStack and HStack as long as I use .foregroundColor() and add an empty Text(""). Hopefully this hack of using an empty text won't break in the next update :)Shulamith
is there a way to set the accentColor for all navigation views using UIAppearance ?Lithomarge
H
6

Use an empty menu with custom style instead of changing accentColor.

    .toolbar {
         ToolbarItem(placement: .navigationBarTrailing) {
             Menu(content: {
              
             }, label: {
                Text("Hello")
             })
             .menuStyle(RedMenuStyle())
         }
     }



struct RedMenuStyle : MenuStyle {
    func makeBody(configuration: Configuration) -> some View {
        Menu(configuration)
            .font(Font.system(size: 50))
            .foregroundColor(Color.red)
    }
}

Use navigationBarItems should you dispaly only text.

    .navigationBarItems(leading: Text("Hello")
                                 .foregroundColor(Color.red)
                                 .font(Font.system(size: 50)))
Hooked answered 26/11, 2020 at 18:38 Comment(0)
G
3

For me it worked using tint:

.toolbar {
    ToolbarItem(placement: .navigationBarLeading) {
        Button {

        } label: {
            Image(systemName: "arrow.backward")
                .bold()
        }
    }
}
.tint(.white)
Gilleod answered 12/7, 2023 at 19:58 Comment(0)
H
1

Considering, that ToolbarItem does not have any modifiers available, the only possible solution I see is using UIViewRepresentable that seems to ignore toolbars modifications:

.toolbar {
   ToolbarItem(placement: .navigationBarLeading) {
      TitleRepresentation(title: "Test", titleColor: .red)
   }
}

...

struct TitleRepresentation: UIViewRepresentable {
    let title: String
    let titleColor: UIColor
    
    func makeUIView(context: Context) -> UILabel {
        let label = UILabel()
        label.tintColor = titleColor
        label.text = title
        return label
    }
    
    func updateUIView(_ uiView: UILabel, context: Context) {}

    typealias UIViewType = UILabel
}
Hemophilia answered 21/10, 2020 at 17:6 Comment(1)
This didnt work for me. Can you provide whole struct with toolbar?Kilauea
A
0

Use a foreground style instead of foreground color.

.toolbar(content: {
                ToolbarItem(placement: .topBarLeading) {
                    Image(systemName: "camera.fill")
                        .foregroundStyle(.blue)
                }
                ToolbarItem(placement: .principal) {
                    Text("Signal Cleanup")
                }
                ToolbarItem(placement: .topBarTrailing) {
                    Image(systemName: "heart.fill")
                        .foregroundStyle(.blue)
                }
            })
Alary answered 11/6, 2024 at 10:0 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.