84

I am trying to build my own custom tab bar view, while building my custom buttons I am unable to change the color of Image().

struct TabBarButton: View {
      let title: String
      let icon: String
    
      
      var body: some View {
        return GeometryReader{ geometry in
           VStack {
            Image(self.icon)
              .resizable()
              .aspectRatio(contentMode: .fit)
              .frame(width: geometry.size.width/2, height: CGFloat(25))
              .foregroundColor(.white)
               
            Text(self.title)
                .font(.system(size: 8))
                .foregroundColor(Color.white)
          }
      }
    }
      
  }

I have tried foregroundColor(Color.white), accentColor(Color.white), as well as some different color multipliers. Is there a reason the color isn't anything other than default black? Easy fix is just to get white icons but I was hoping to solve this.

DischordDynne
  • 117
  • 15
C. Skjerdal
  • 2,750
  • 3
  • 25
  • 50

8 Answers8

221

I'm not sure what are you trying to to achieve, but probably you just need template rendering mode, like

Image(self.icon)
    .renderingMode(.template)
    .foregroundColor(.white)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • 1
    Yes that's perfect, I was just trying to dynamically change the colours of custom tab buttons. This way I can swap colours when selected rather than swap the icon. – C. Skjerdal Jan 29 '20 at 19:46
  • 2
    I didn't know I had to set `.foregroundColor()`. I assumed it would automatically use `Color.accentColor` once the `renderingMode` has been set. Whenever I put an `Image` view as a `Button`'s label it would just do exactly that, but without a button the `Image` needs `.foregroundColor()` to be set. – iMaddin May 27 '20 at 03:32
25

In assets on import icon (import from *.pdf), set up Image Set → Render as → Template Image

enter image description here

In the code:

Image("ImageFileName")

Or: You can add the "Template" suffix and set "Rednder as default". In documentation

if the name of the image ends in "Template", use the image as a template, otherwise render it as the original image

and in code:

Image("ImageFileNameTemplate")
DischordDynne
  • 117
  • 15
flyer2001
  • 451
  • 6
  • 12
13

Single Color Images (like icons and symbols)

For setting the color to single-color images with the foregroundColor modifier, you should make sure that image renderingMode is set to template

with code:
Image("Star")
    .renderingMode(.template)
    .foregroundColor(.yellow)

or

With Assets Catalogue properties:

Assets Catalogue Rendering Mode

Note that the image MUST have the alpha channel (like PNG or PDF), otherwise you will get a colored rectangle!


Multi-Color Symbols

From iOS 15, Apple introduced symbols with more rendering mode support. you can create one or change one and export it from the SF Symbols.app:

SF Symbols Demo

And you can also use up to 3 colors directly in the code like:

SF Symbols Demo


Recolor a Colorful Image!

SwiftUI is so easy and powerful and you can recolor an image in no time with a few modifiers like the blendingMode:

Blending examole

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
3

You are making something that should look and behave like button. Why not make it a button right from the start, so you can reuse such kind of buttons wherever you like?

struct TabBarButton: ButtonStyle {
    var icon: String = "" // you a free to provide a reasonable default
    
    func makeBody(configuration: Self.Configuration) -> some View {
        GeometryReader{ geometry in
            VStack {
                Image(systemName: icon)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: geometry.size.width/2, height: CGFloat(25)) // I didn't put therse magic numbers here
                    .foregroundColor(.green) // not very stylish but the color is a at your control
                
                configuration.label
                    .font(.system(size: 8)) // and here
                    .foregroundColor(Color.black)
            }
        }
    }
}

Use as usual button with title, action {}.

    Button("Tab Bar Button") {
        // action code here
    }
    .buttonStyle(TabBarButton(icon: "info.circle"))

Here is an example of adding custom button to Navigation Bar:

struct TabBarButton: PrimitiveButtonStyle {
    var icon: String = "" // you a free to provide a reasonable default
    func makeBody(configuration: Self.Configuration) -> some View {
        VStack {
            Image(systemName: icon)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .foregroundColor(.green) // Changes color in NavBar
            configuration.label
                .foregroundColor(Color.black)
        }
    }
}

And in ContentView add:

    .navigationBarItems(trailing: Button(action: {}, label: {
        Text("Some")
    }).buttonStyle(TabBarButton(icon: "info.circle")))

The result looks like this: ToolBarCustomButton

Paul B
  • 3,989
  • 33
  • 46
  • At the time there might have been a reason to avoid this, none the less this is the recommended implementation for custom buttons. However this doesn't include the fix of using .renderingMode(.template) which was the bigger issue all along. – C. Skjerdal Nov 30 '20 at 19:10
3

iOS 15+

Some symbols has multiple layers. You need to use .symbolRenderingMode(.palette) and set the color of each of the layers using .foregroundStyle() view modifier explicitly

     Image(systemName: "cloud.sun.fill")
            .symbolRenderingMode(.palette)
            .foregroundStyle(.black, .yellow)
mahan
  • 12,366
  • 5
  • 48
  • 83
0

this code will add any color to the image just change the name with color-name

Image("Name")
    .resizable()
    .foregroundColor(Color.name)
  • As in the question I have tried this "I have tried foregroundColor(Color.white)". Unless Swiftui has changed, I had to use .renderingMode(.template) to solve this. – C. Skjerdal Dec 03 '20 at 16:40
-1

Here the code:

Image("profile_photo").resizable()
.renderingMode(.template)
.foregroundColor(.blue)
.scaledToFill() 
.frame(width: 120, height: 120,alignment: .center)
.clipShape(Circle())
juagicre
  • 1,065
  • 30
  • 42
indrit saveta
  • 127
  • 1
  • 6
-1

you just need template rendering mode. nothing else

Image(your image)
    .renderingMode(.template)
    .do anything you need to update
Al Mustakim
  • 480
  • 4
  • 11