iosswiftswiftuidarkmode

SwiftUI's preferredColorScheme does not work for TabView's Tab Bar


I want to include an app appearance picker in my SwiftUI app. It should let the user choose between

I've tried to implement it using the preferredColorScheme modifier, as you can see in the sample code below.

For the most part, it seems to works fine. However, the bottom tab bar of my TabView does not seem to respect the setting.

Is there any way to fix this behavior?

import SwiftUI

struct ContentView: View {
    
    @State var selectedTab: Int
    @AppStorage("selectedAppAppearance") var selectedAppAppearance: String = "system"

    
    var body: some View {
        TabView(selection: $selectedTab) {
            Form {
                Section(header: Text("Section 1")) {
                    Picker("Appearance", selection: $selectedAppAppearance) {
                        Text("Light")
                            .tag("light")
                        Text("Dark")
                            .tag("dark")
                        Text("System")
                            .tag("system")
                    }
                }
                Section(header: Text("Section 2")) {
                    ForEach(1..<20) { index in
                        Text("Row \(index)")
                    }
                }
            }
            .tabItem {
                VStack {
                    Image(systemName: "1.circle")
                    Text("First")
                }
            }
            .tag(1)
            ScrollView {
                
            }
            .tabItem {
                    VStack {
                        Image(systemName: "2.circle")
                        Text("Second")
                    }
                }
        }
        .preferredColorScheme(getColorScheme(input: selectedAppAppearance))
    }
    
    private func getColorScheme(input: String) -> ColorScheme? {
        switch input {
        case "light":
            return .light
        case "dark":
            return .dark
        default:
            return nil
        }
    }
    
}

#Preview {
    ContentView(selectedTab: 1)
}

Color Scheme picker in action


Solution

  • It helps if you specify the .toolbarBackground explicitly. This needs to be applied to each of the child views of the TabView:

    TabView(selection: $selectedTab) {
        Form {
            // ...
        }
        .tabItem {
            // ...
        }
        .toolbarBackground(.bar, for: .tabBar) // 👈 HERE
        .tag(1)
    
        // ...
    }
    .preferredColorScheme(getColorScheme(input: selectedAppAppearance))