在 SwiftUI 中添加 Dark Mode 最佳实践

了解如何在 SwiftUI 中为应用添加黑暗模式,并学习如何使颜色能够自适应外观模式而切换。

在 SwiftUI 中添加 Dark Mode 最佳实践

使用 SwiftUI 开发 iOS 应用,添加黑暗模式效果非常简单,SwiftUI 提供了自动适应系统外观变化的能力,在大部分情况下,你无需格外工作即可自动应用黑暗模式。

但在实践中,仍然存在一些使用技巧和颜色搭配原则,遵循这些技巧和原则,可以让应用表现更加出众。

颜色搭配原则

巧妙地使用颜色可以增强沟通感,体现品牌形象,提供视觉连续性,传达状态和反馈,以及帮助用户理解信息。

Apple 颜色设计规范:

颜色 | Apple Developer Documentation
巧妙地使用颜色可以增强沟通感,体现品牌形象,提供视觉连续性,传达状态和反馈,以及帮助用户理解信息。

Dark Mode 设计原则:

深色模式 | Apple Developer Documentation
深色模式是一种系统范围的外观设置,使用深色调色盘为低光环境提供舒适的浏览体验。

优先使用系统自适应颜色

如果使用指定颜色(例如 Color.white),会导致组件无法自动适配系统的浅色/深色模式而动态变化。

在下面这个示例中,最开始我使用 .background(Color.white) 为卡片设置了白色的背景色。这在浅色模式下表现良好,但当开启黑暗模式,就会显得非常突兀,因为 Color.white 不会自适应外观模式进行调整:

为了解决这个问题,推荐优先使用 Color 的自适应系统颜色,这些颜色会自动根据当前的外观模式(Light Mode 和 Dark Mode)进行调整。

例如,使用Color(.systemBackground) ,能够保证在浅色模式和深色模式下都有很好的可读性:

Apple 原生应用风格的颜色搭配最佳实践

你当然也可以使用自定义颜色,来为你的 App 创建独特的外观。但颜色的合理搭配是一门学问,如果你没有这方面的专业知识,也不想专门去了解,建议优先使用 Apple 推荐的颜色搭配。

Apple 推荐的背景色与前景色,在不同外观模式下的搭配是这样的:

在浅色模式下:

  • 系统背景为浅灰色
  • 内容块背景为纯白色

在深色模式下:

  • 系统背景为纯黑色
  • 内容块背景为浅灰色。

iPhone 上的几乎所有 Apple 原生应用,都遵循这套颜色使用原则。

为了实现以上效果,可以组合使用:

  • .background(Color(.systemGroupedBackground)) (用作系统背景颜色)
  • .background(Color(.secondarySystemGroupedBackground)) (用作内容块背景颜色)

例如下面这个实例代码:

import SwiftUI

struct SettingsView: View {
    var body: some View {
        List {
            Section(header: Text("账号设置")) {
                HStack {
                    Text("用户名")
                    Spacer()
                    Text("john_doe")
                        .foregroundColor(.gray)
                }
                HStack {
                    Text("电子邮箱")
                    Spacer()
                    Text("john@example.com")
                        .foregroundColor(.gray)
                }
            }
            .background(Color(.secondarySystemGroupedBackground))

            Section(header: Text("应用设置")) {
                Toggle("推送通知", isOn: .constant(true))
                Toggle("使用蜂窝数据", isOn: .constant(false))
            }
            .background(Color(.secondarySystemGroupedBackground))

            Section(header: Text("隐私")) {
                NavigationLink(destination: Text("隐私政策详情")) {
                    Text("隐私政策")
                }
                NavigationLink(destination: Text("条款与条件")) {
                    Text("条款与条件")
                }
            }
            .background(Color(.secondarySystemGroupedBackground))
        }
        .listStyle(GroupedListStyle())
        .background(Color(.systemGroupedBackground))
    }

}

struct SettingsView_Previews: PreviewProvider {
    static var previews: some View {
        SettingsView()
            .preferredColorScheme(.light)  // 预览浅色模式
        SettingsView()
            .preferredColorScheme(.dark)  // 预览深色模式
    }
}

自适应外观模式颜色列表

SwiftUI 提供了许多能够自动适应系统外观模式(浅色和深色模式)的颜色,这些颜色会根据用户的设置自动调整,以确保在不同的环境下都有良好的可读性和一致的视觉体验。

以下是 SwiftUI 中常用的自适应外观模式的颜色,每个颜色在不同外观模式下的表现,可以参考附录。

文本颜色

Color.primary

用途:主要内容的前景色,通常用于文本。

效果:浅色模式下为黑色,深色模式下为白色。

Color.secondary

用途:次要内容的前景色,比 primary 更淡。

效果:颜色会根据模式自动调整。

Color.accentColor

用途:应用的强调色,可用于按钮、链接等需要突出的元素。

设置:可在 Assets.xcassets 中全局设置。

系统背景颜色

Color(.systemBackground)

用途:视图的背景色。

效果:浅色模式下为白色,深色模式下为黑色。

Color(.secondarySystemBackground)

用途:次级内容的背景色。

效果:颜色会根据模式自动调整。

Color(.tertiarySystemBackground)

用途:分组内容的背景色。

系统分组背景颜色

Color(.systemGroupedBackground)

用途:用于分组列表的背景。

Color(.secondarySystemGroupedBackground)

用途:次级分组背景色。

Color(.tertiarySystemGroupedBackground)

用途:三级分组背景色。

标签颜色

Color(.label)

用途:主要文本颜色。

Color(.secondaryLabel)

用途:次要文本颜色。

Color(.tertiaryLabel)

用途:三级文本颜色。

Color(.quaternaryLabel)

用途:四级文本颜色。

填充颜色

Color(.systemFill)

用途:含有内容的元素的背景色,例如输入框。

Color(.secondarySystemFill)

用途:次级填充色。

Color(.tertiarySystemFill)

用途:三级填充色。

Color(.quaternarySystemFill)

用途:四级填充色。

分隔线颜色

Color(.separator)

用途:一般分隔线颜色。

Color(.opaqueSeparator)

用途:不透明的分隔线颜色。

链接颜色

Color(UIColor.link)

用途:可点击的链接文本颜色。

附录

系统颜色预览表