Change color of image (icon) in tabItems in SwiftUI
Asked Answered
D

3

6

How can i change the color of the image (icon) in the tabItems in SwiftUI?

I tried so many things and nothing works...

Thanks

Here is my test code :

import SwiftUI

struct TestTabviewIconColor: View {

    var body: some View {
        TabView {
            Text("The First Tab")
                .tabItem {
                    Image(systemName: "1.square.fill")
                        .foregroundColor(.red)
                        .accentColor(.red)
                        .colorMultiply(.red)
                    Text("First")
            }
            Text("Another Tab")
                .tabItem {
                    Image(systemName: "2.square.fill")
                    Text("Second")
                }
            Text("The Last Tab")
                .tabItem {
                    Image(systemName: "3.square.fill")
                    Text("Third")
                }
        }
        .font(.headline)
    }
}

struct TestTabviewIconColor_Previews: PreviewProvider {
    static var previews: some View {
        TestTabviewIconColor()
    }
}

Deduction answered 22/3, 2020 at 19:8 Comment(0)
V
5

If you want to have different TabBar button colors when the tab is selected than I'm reasonably confident that the Apple provided control won't do that for you.

You'll need to roll your own control. This is fairly straightforward. For an example with a THREE tabs see the code below. If you're working with a fixed number of tabs this approach might work for you. And the principles could be applied to build a control for more and variable number of tabs using @ViewBuilder etc.

I've approximated the styling of the stock TAB bar. You'd need to do a bit of refinement to look exactly the same if that's important for your use case.

struct TabLabel : View {

      var text : String
      var imageName : String
      var color : Color

      var body : some View {
            VStack() {
                  Image(systemName: imageName)
                  Text(text).font(.caption)
            }.foregroundColor(color)
      }
}

struct TabButton : View {
      @Binding var currentSelection : Int
      var selectionIndex : Int
      var label : TabLabel

      var body : some View {
            Button(action: { self.currentSelection = self.selectionIndex }) { label }.opacity(selectionIndex == currentSelection ? 0.5 : 1.0)
      }
}

struct CustomTabBarView<SomeView1 : View, SomeView2 : View, SomeView3 : View> : View {

      var view1 : SomeView1
      var view2 : SomeView2
      var view3 : SomeView3

      @State var currentSelection : Int = 1
      var body : some View {

            let label1 = TabLabel(text: "First", imageName:  "1.square.fill", color: Color.red)
            let label2 = TabLabel(text: "Second", imageName:  "2.square.fill", color: Color.purple)
            let label3 = TabLabel(text: "Third", imageName:  "3.square.fill", color: Color.blue)

            let button1 = TabButton(currentSelection: $currentSelection, selectionIndex: 1, label: label1)
            let button2 = TabButton(currentSelection: $currentSelection, selectionIndex: 2, label: label2)
            let button3 = TabButton(currentSelection: $currentSelection, selectionIndex: 3, label: label3)


            return VStack() {

                  Spacer()

                  if currentSelection == 1 {
                        view1
                  }
                  else if currentSelection == 2 {
                        view2
                  }
                  else if currentSelection == 3 {
                        view3
                  }

                  Spacer()

                  HStack() {
                        button1
                        Spacer()
                        button2
                        Spacer()
                        button3

                  }.padding(.horizontal, 48)
                        .frame(height: 48.0)
                        .background(Color(UIColor.systemGroupedBackground))
            }

      }
}


struct ContentView: View {

      var body: some View {

            let view1 = VStack() {
                  Text("The First Tab").font(.headline)
                  Image(systemName: "triangle").resizable().aspectRatio(contentMode: .fit).frame(width: 100)
            }

            let view2 = Text("Another Tab").font(.headline)
            let view3 = Text("The Final Tab").font(.headline)

            return CustomTabBarView(view1: view1, view2: view2, view3: view3)
      }

}


struct ContentView_Previews: PreviewProvider {
      static var previews: some View {
            ContentView()
      }
}
Violante answered 24/3, 2020 at 14:42 Comment(3)
Hi Obliquely, Your solution work with system images... My images are not system images but icons that i put on Assets.xcassets. Why it is not working with them? Thanks FlincorpDeduction
I'd guess that your images aren't formatted in quite the right way. They need to be "monochromatic image with transparency, anti-aliasing, and no drop shadow that uses a mask to define its shape." (developer.apple.com/design/human-interface-guidelines/ios/…) You could also create your icons as custom symbols images (developer.apple.com/documentation/uikit/uiimage/…) - these will then behave like the SF Font system images.Violante
They worked nice on normal Swift... I will use SF Symblos for SwiftUI and IOS 13 and later.... :-\. Thank you very much for your help.Deduction
C
6

For change tint color of tabbar, you just need set .accentColor() modifier for the TabView to apply on items.

Cluck answered 22/3, 2020 at 20:41 Comment(1)
Thank you! I was just looking to the simplest color change and that is it!Turboelectric
V
5

If you want to have different TabBar button colors when the tab is selected than I'm reasonably confident that the Apple provided control won't do that for you.

You'll need to roll your own control. This is fairly straightforward. For an example with a THREE tabs see the code below. If you're working with a fixed number of tabs this approach might work for you. And the principles could be applied to build a control for more and variable number of tabs using @ViewBuilder etc.

I've approximated the styling of the stock TAB bar. You'd need to do a bit of refinement to look exactly the same if that's important for your use case.

struct TabLabel : View {

      var text : String
      var imageName : String
      var color : Color

      var body : some View {
            VStack() {
                  Image(systemName: imageName)
                  Text(text).font(.caption)
            }.foregroundColor(color)
      }
}

struct TabButton : View {
      @Binding var currentSelection : Int
      var selectionIndex : Int
      var label : TabLabel

      var body : some View {
            Button(action: { self.currentSelection = self.selectionIndex }) { label }.opacity(selectionIndex == currentSelection ? 0.5 : 1.0)
      }
}

struct CustomTabBarView<SomeView1 : View, SomeView2 : View, SomeView3 : View> : View {

      var view1 : SomeView1
      var view2 : SomeView2
      var view3 : SomeView3

      @State var currentSelection : Int = 1
      var body : some View {

            let label1 = TabLabel(text: "First", imageName:  "1.square.fill", color: Color.red)
            let label2 = TabLabel(text: "Second", imageName:  "2.square.fill", color: Color.purple)
            let label3 = TabLabel(text: "Third", imageName:  "3.square.fill", color: Color.blue)

            let button1 = TabButton(currentSelection: $currentSelection, selectionIndex: 1, label: label1)
            let button2 = TabButton(currentSelection: $currentSelection, selectionIndex: 2, label: label2)
            let button3 = TabButton(currentSelection: $currentSelection, selectionIndex: 3, label: label3)


            return VStack() {

                  Spacer()

                  if currentSelection == 1 {
                        view1
                  }
                  else if currentSelection == 2 {
                        view2
                  }
                  else if currentSelection == 3 {
                        view3
                  }

                  Spacer()

                  HStack() {
                        button1
                        Spacer()
                        button2
                        Spacer()
                        button3

                  }.padding(.horizontal, 48)
                        .frame(height: 48.0)
                        .background(Color(UIColor.systemGroupedBackground))
            }

      }
}


struct ContentView: View {

      var body: some View {

            let view1 = VStack() {
                  Text("The First Tab").font(.headline)
                  Image(systemName: "triangle").resizable().aspectRatio(contentMode: .fit).frame(width: 100)
            }

            let view2 = Text("Another Tab").font(.headline)
            let view3 = Text("The Final Tab").font(.headline)

            return CustomTabBarView(view1: view1, view2: view2, view3: view3)
      }

}


struct ContentView_Previews: PreviewProvider {
      static var previews: some View {
            ContentView()
      }
}
Violante answered 24/3, 2020 at 14:42 Comment(3)
Hi Obliquely, Your solution work with system images... My images are not system images but icons that i put on Assets.xcassets. Why it is not working with them? Thanks FlincorpDeduction
I'd guess that your images aren't formatted in quite the right way. They need to be "monochromatic image with transparency, anti-aliasing, and no drop shadow that uses a mask to define its shape." (developer.apple.com/design/human-interface-guidelines/ios/…) You could also create your icons as custom symbols images (developer.apple.com/documentation/uikit/uiimage/…) - these will then behave like the SF Font system images.Violante
They worked nice on normal Swift... I will use SF Symblos for SwiftUI and IOS 13 and later.... :-\. Thank you very much for your help.Deduction
B
1

Try changing rendering mode of the image: In Assets.xcassets select the image, open inspectors view and switch to attribute inspector Then select Render As: Template Image

This worked for me.

Boogiewoogie answered 28/2, 2022 at 21:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.