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)
}
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))