I was trying to change the tint color of an unselected item in SwiftUI.
Currently, I got it so it has a background and changes the tint color (making the tab bar visible in .tabItem gets rid of the .red tint and makes it gray)
import SwiftUI
import UIKit
struct Test: View{
    
    init(){
        UITabBar.appearance().backgroundColor = UIColor.systemBackground
        UITabBar.appearance().unselectedItemTintColor = .red
    }
    
    var body: some View{
        
        TabView{
            Text("1")
                .tabItem{
                    Image(systemName: "heart.fill")
                    Text("Heart")
                }
              
                
            Text("2")
                .tabItem{
                    Image(systemName: "gearshape.fill")
                    Text("Settings")
                }
        }
    }
}
#Preview{
    Test()
}

Now I'm trying to add the divider line that separates the tab bar with the rest of the stuff on the page. Doing .toolbarBackground(.visible, for: .tabBar) brings back the divider, but then the unselected item tint doesn't work anymore.
TabView{
            Text("1")
                .tabItem{
                    Image(systemName: "heart.fill")
                    Text("Heart")
                }
                .toolbarBackground(.visible, for: .tabBar)

I also tried doing this method but it seems like it doesn't work anymore.
I would just abandon the native tab bar and use a custom one. Then you can style it any way you like.
LabelStyle can be used to style the labels of the buttons.Something like:
enum TabType: CaseIterable {
    case heart
    case settings
    var titleKey: String {
        "\(self)".capitalized
    }
    var symbolName: String {
        switch self {
        case .heart: "heart"
        case .settings: "gearshape"
        }
    }
}
struct TabLabelStyle: LabelStyle {
    let isSelected: Bool
    func makeBody(configuration: Configuration) -> some View {
        VStack(spacing: 4) {
            configuration.icon
                .imageScale(.large)
            configuration.title
                .font(.caption)
        }
        .symbolVariant(isSelected ? .fill : .none)
        .foregroundStyle(isSelected ? Color.accentColor : .red)
        .frame(maxWidth: .infinity)
    }
}
struct CustomTabBar: View {
    @Binding var selection: TabType
    var body: some View {
        HStack {
            ForEach(TabType.allCases, id: \.self) { type in
                Button {
                    withAnimation(.spring) {
                        selection = type
                    }
                } label: {
                    Label(type.titleKey, systemImage: type.symbolName)
                        .labelStyle(TabLabelStyle(isSelected: selection == type))
                }
            }
        }
        .padding()
        .background(.bar)
        .overlay(alignment: .top) { Divider() }
    }
}
The custom tab bar can be attached to the main content using .safeAreaInset(edge: .bottom).
TabView if you like. This might have some advantages in terms of preserving state (such as, preserving scroll position). When doing it this way, the native tab bar must be hidden for every child view:struct ContentView: View {
    @State private var selection = TabType.heart
    var body: some View {
        TabView(selection: $selection) {
            Text("1")
                .tag(TabType.heart)
                .toolbarVisibility(.hidden, for: .tabBar)
                // pre iOS 18: .toolbar(.hidden, for: .tabBar)
            Text("2")
                .tag(TabType.settings)
                .toolbarVisibility(.hidden, for: .tabBar)
        }
        .safeAreaInset(edge: .bottom) {
            CustomTabBar(selection: $selection)
        }
    }
}
ZStack. This allows you to determine the transition when switching:ZStack {
    switch selection {
    case .heart:
        Text("1")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .transition(.move(edge: .leading))
    case .settings:
        Text("2")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .transition(.move(edge: .trailing))
    }
}
.safeAreaInset(edge: .bottom) {
    CustomTabBar(selection: $selection)
}

If you want to use a sliding transition for three or more tabs, you might find the answer to SwiftUI bi-directional move transition moving the wrong way in certain cases useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With