SwiftUI 暗模式:完整实现指南

发布: (2026年2月1日 GMT+8 02:37)
2 min read
原文: Dev.to

Source: Dev.to

检测当前颜色方案

SwiftUI 提供 @Environment(\.colorScheme) 来检测应用是处于浅色模式还是深色模式。

struct ContentView: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Text("Hello")
            .foregroundColor(colorScheme == .dark ? .white : .black)
    }
}

使用自适应颜色

与其手动检查颜色方案,不如依赖 SwiftUI 内置的自适应颜色。

Text("Adapts automatically")
    .foregroundColor(.primary)                     // 浅色时为黑色,深色时为白色
    .background(Color(.systemBackground))        // 浅色时为白色,深色时为黑色

关键语义颜色

  • .primary / .secondary – 自动适配的文本颜色。
  • Color(.systemBackground) – 主背景颜色。
  • Color(.secondarySystemBackground) – 分组内容的背景颜色。

创建自定义主题

若需要对颜色进行完全控制,可定义一个主题结构体。

struct AppTheme {
    let background: Color
    let text: Color
    let accent: Color

    static let light = AppTheme(
        background: .white,
        text: .black,
        accent: .blue
    )

    static let dark = AppTheme(
        background: Color(.systemGray6),
        text: .white,
        accent: .cyan
    )
}

通过 Environment 提供主题

定义一个 EnvironmentKey 并扩展 EnvironmentValues 来存储当前主题。

struct ThemeKey: EnvironmentKey {
    static let defaultValue = AppTheme.light
}

extension EnvironmentValues {
    var theme: AppTheme {
        get { self[ThemeKey.self] }
        set { self[ThemeKey.self] = newValue }
    }
}

预览两种模式

始终在浅色和深色外观下测试你的 UI。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
                .preferredColorScheme(.light)

            ContentView()
                .preferredColorScheme(.dark)
        }
    }
}

常见陷阱

  • 硬编码颜色 – 更倾向使用语义颜色(.primary.secondary、系统背景颜色),它们会自动适配。
  • 缺少图像资源 – 为深色模式提供变体或使用 SF Symbols,后者默认会自适应。
  • 跳过预览 – 始终预览浅色和深色方案,以便及早发现视觉问题。
Back to Blog

相关文章

阅读更多 »

[SUI] 搜索栏

NavigationStack 中的搜索栏 NavigationStack 可以通过 `searchable` 修饰符添加搜索栏。它的签名是:swift searchable t...

2026 年如何构建 SwiftUI 项目

问题 Xcode 只给你 ContentView.swift,仅此而已。随着你的应用增长,你会出现以下情况:- 一个文件夹里有 50 个文件 - ViewModel 与 View 混在一起 - 没有 cl...