I want my app to support both light and dark themes, where users can change the theme to their preference or keep it as the default system theme. When users switch the theme to dark or light mode, the app should remember their choice and apply the same theme the next time they open the app. And I don't want to change it for every single view instead I want it for whole app. Now its changing the theme but when I reopened the app it sets to default.
I changing the theme like this :
struct Settings1: View {
@Environment(\.colorScheme) private var colorScheme
var body: some View {
VStack(alignment: .leading){
Text("Select Mode")
.font(.custom("Inter-Medium", size: 22))
Spacer()
Button {
changeTheme(to: .dark)
} label: {
HStack{
ZStack{
Circle()
.fill(colorScheme == .dark ? Color.green:Color.gray)
.frame(width:32 ,height: 32)
Circle()
.fill(Color.black)
.frame(width:30 ,height: 30)
}
Text("Dark Mode")
.font(.custom("Inter-Medium", size: 19))
.foregroundColor(Color("dayNightText"))
.padding(.leading)
Spacer()
}
}
Button {
changeTheme(to: .light)
} label: {
HStack{
ZStack{
Circle()
.fill(colorScheme == .light ? Color.green:Color.gray)
.frame(width:32 ,height: 32)
Circle()
.fill(Color.white)
.frame(width:30 ,height: 30)
}
Text("White Mode")
.font(.custom("Inter-Medium", size: 19))
.foregroundColor(Color("dayNightText"))
.padding(.leading)
Spacer()
}
}
Button {
changeTheme(to: .device)
} label: {
HStack{
ZStack{
Circle()
.fill(colorScheme == .light ? Color.green:Color.gray)
.frame(width:32 ,height: 32)
Circle()
.fill(Color.white)
.frame(width:30 ,height: 30)
}
Text("System Default")
.font(.custom("Inter-Medium", size: 19))
.foregroundColor(Color("dayNightText"))
.padding(.leading)
Spacer()
}
}
Spacer()
}
.frame(width: 300, height: 300)
.background(Color.gray.ignoresSafeArea())
.cornerRadius(30)
}
func changeTheme(to theme: Theme) {
UserDefaults.standard.theme = theme
UIApplication.shared.windows.first?.overrideUserInterfaceStyle = theme.userInterfaceStyle
}
}
struct Settings1_Previews: PreviewProvider {
static var previews: some View {
Settings1()
}
}
enum Theme: Int {
case device
case light
case dark
}
extension Theme {
var userInterfaceStyle: UIUserInterfaceStyle {
switch self {
case .device:
return .unspecified
case .light:
return .light
case .dark:
return .dark
}
}
}
extension UserDefaults {
var theme: Theme {
get {
register(defaults: [#function: Theme.device.rawValue])
return Theme(rawValue: integer(forKey: #function)) ?? .device
}
set {
set(newValue.rawValue, forKey: #function)
}
}
}
and then on re launch trying to recover the previous one but its not working
import SwiftUI
@main
struct TestApp: App {
init(){
let savedTheme = UserDefaults.standard.theme
UIApplication.shared.windows.first?.overrideUserInterfaceStyle = savedTheme.userInterfaceStyle
}
var body: some Scene {
WindowGroup {
NavigationView{
Settings1()
}
}
}
}
.preferredColorScheme()
. In order to have the third optiondevice
, you can use a view modifier to alternately inject the.preferredColorScheme()
into the top view in the @ main file.UIApplication.shared.windows.first
is deprecated. Even on iPhone, it is possible to have more than 1 window, so using first may not cut it. – Aquileia