如何为SwiftUI应用设置偏好ColorScheme(亮色/暗色/系统)
解决SwiftUI中ColorScheme偏好设置无法跟随系统更新的问题
你的代码核心问题在于:当通过.preferredColorScheme(preferredDesign)手动指定颜色方案后,@Environment(\.colorScheme)获取到的是你设置的值,而非系统真实的颜色方案状态,所以onChange无法监听到系统模式的变化。
正确的做法是利用preferredColorScheme的可选特性:当传入nil时,应用会自动跟随系统的颜色方案,无需手动同步系统状态。下面是优化后的实现:
import SwiftUI // 定义清晰的偏好枚举,替代原有的Int标记 enum ColorSchemePreference: CaseIterable { case system, light, dark var displayName: String { switch self { case .system: return "System" case .light: return "Hell" case .dark: return "Dunkel" } } } struct ContentView: View { // 存储用户的偏好选择 @State private var selectedPreference: ColorSchemePreference = .system // 获取当前系统(或应用)的颜色方案,仅用于展示或其他逻辑 @Environment(\.colorScheme) var currentColorScheme // 根据用户偏好返回对应的ColorScheme?,system模式返回nil让系统控制 private var preferredColorScheme: ColorScheme? { switch selectedPreference { case .system: return nil case .light: return .light case .dark: return .dark } } var body: some View { VStack { Form { HStack { Text("Design") .frame(maxWidth: 100, alignment: .leading) Spacer() Picker("Design Picker", selection: $selectedPreference) { ForEach(ColorSchemePreference.allCases, id: \.self) { preference in Text(preference.displayName).tag(preference) } } .pickerStyle(SegmentedPickerStyle()) } .padding(.vertical, 13) } Divider() Image(systemName: "globe") .imageScale(.large) .foregroundColor(.accentColor) Text("Hello, world! Current scheme: \(currentColorScheme == .light ? "Light" : "Dark")") } .padding() // 应用用户偏好的颜色方案,nil时跟随系统 .preferredColorScheme(preferredColorScheme) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { Group { ContentView() .preferredColorScheme(.light) ContentView() .preferredColorScheme(.dark) } } }
关键优化点:
- 使用
ColorSchemePreference枚举替代Int,让代码更易读、不易出错 - 当用户选择"System"时,
preferredColorScheme返回nil,此时应用会自动跟随系统的颜色变化,无需额外监听同步 - 移除了冗余的
systemDesign状态,简化了逻辑 - 预览部分同时展示亮色和暗色模式的效果,方便调试
测试效果:
- 选择"System"后,切换系统的暗色模式,应用会自动切换对应的配色
- 选择"Hell"或"Dunkel"时,应用会固定在对应的模式,不受系统设置影响
内容的提问来源于stack exchange,提问作者neldierto
相关产品推荐
相关产品推荐

