45

I am looking for a way to change the stroke / fill color of an SF Symbol icon in SwiftUI.

I have tried .background(Color.red) but that just changes the background of the whole icon (no change is applied to the actual icon itself) as implied. I also tried .foregroundColor(Color.red)which does nothing to the icon.

contents of content view are as follows:

var body: some View {
    Image(systemName: "person.circle").foregroundColor(.red)    
}
pkamb
  • 33,281
  • 23
  • 160
  • 191

8 Answers8

49

You can change the stroke and fill color of a sf symbol icon using foregroundColor(_ color: Color?)

The following code:

Image(systemName: "flame.fill").foregroundColor(.red)
Image(systemName: "flame").foregroundColor(.red)

Should produce this:

Filled and Stroked Flame SF Symbol Icons

Here is the complete SwiftUI View Code

struct Icon : View {
    var body: some View {
        HStack{
            Image(systemName: "flame.fill")
            .foregroundColor(.red)
            Image(systemName: "flame")
            .foregroundColor(.red)
        }
        .padding()
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209
Noemi Quezada
  • 503
  • 3
  • 5
  • Perfect. `foregroundColor` did the trick for me. You would say `accentColor` would describe this functionality better but that one doesn't work. – Ramon Aug 21 '19 at 20:51
  • Also note that `foregroundColor` has no effect on Image if you use a `Image(uiImage: UiImage("flame.fill"))` – Thomas Dec 16 '20 at 15:11
  • The SFSymbol `.fill` or `.outline` variants are now automatically selected depending on the containing view. e.g. in `TabView` on Mac. Mac and iOS tab views don't both use `.fill`. – Pranav Kasetti Jun 10 '21 at 14:34
  • 1
    @Thomas you can get past the `foregroundColor` not working with a UIImage source by setting the rendering mode, e.g. `Image(uiImage: UiImage("flame.fill")).renderingMode(.template).foregroundColor(Color(.red))`. I still have some programatically created icons generated with PaintCode returned as UIImages. – Kpalser Sep 12 '21 at 18:45
18

iOS 15

from iOS 15 and with the SFSymbols 3, you can apply different layers of colors to a single symbol with the foreground style modifier:

Image(systemName: "person.circle")
    .resizable()
    .foregroundStyle(.red, .blue)
    .frame(width: 200, height: 200, alignment: .center)

Demo 1


iOS 13 and 14

You can use a ZStack with different parts of the icon and apply different modifiers to each layer like:

///  I've used `GeometryReader ` for setting the size of elements dependent on each other

GeometryReader { proxy in 
    ZStack {
        Image(systemName: "circle")
            .resizable()
            .foregroundColor(.blue)

        Image(systemName: "person.fill")
            .resizable()
            .foregroundColor(.red)
            .frame(
                   width: proxy.size.width * 0.55,
                   height: proxy.size.width * 0.55,
                   alignment: .center
            )
    }
}.frame(width: 200, height: 200, alignment: .center)

Demo 2

Note that the old and new methods look slightly different but feel the same. (take a closer look at the roundness of the head)

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
  • using `.resizable` with `systemImage` is not recommended as it's transformed into something other than a font – JAHelia Jun 01 '22 at 06:55
14

iOS 15+

In iOS 15 we can use foregroundStyle to customise SF Symbols even more:

Image(systemName: "cloud.sun.bolt")
    .foregroundStyle(.gray, .blue)

See more at this WWDC session:

enter image description here

pawello2222
  • 46,897
  • 22
  • 145
  • 209
3

One trick I figured out that works nicely for iOS 14 is to use the fill and non fill versions together to get two colors regardless of whether 14 or 15:

ZStack {
    Image(systemName: "person.circle")
        .foregroundColor(.white)
    Image(systemName: "person.circle.fill")
        .foregroundColor(.yellow)
}
Codezy
  • 5,540
  • 7
  • 39
  • 48
2

Yes there is:

var body: some View {
    Image(systemName: "person.circle").accentColor(.red)    
}
Filip Sakel
  • 315
  • 4
  • 8
  • 3
    This worked in an earlier beta. I think that currently, the correct way to do it is to use .foregroundColor(.red). – Filip Sakel Aug 22 '19 at 10:08
0

This will draw the background of the icon in red and the lines in blue:

Image(systemName: "person.circle")
    .foregroundColor(Color.red)
    .background(Color.blue)
    .frame(width: size, height: self, alignment: .center)
    .clipShape(Circle())

Without clipShape there will be blue corners in the rectangle behind the circle.

grebulon
  • 7,697
  • 5
  • 42
  • 66
0

SwiftUI now allows you to color parts (layers) of many of the SF Symbols. Some symbols have many layers.

This will color the symbol foreground blue:

Image(systemName: "person.circle").foregroundStyle(.blue)

If you want to color the circle differently from the person this will color the person blue and the circle gray

Image(systemName: "person.circle").foregroundStyle(.blue, .gray)
Wizkid
  • 1,015
  • 10
  • 10
-1

Just change the tint color. That did it for me.