下面我会为你提供关于 系统主题(System Appearance) 的一篇成体系的内容,涵盖 iOS 和 macOS 中的 深色模式(Dark Mode) 与 浅色模式(Light Mode),以及相关概念、开发注意事项、最佳实践等内容。
系统主题概览:浅色模式和深色模式 #
1. 什么是系统主题? #
系统主题是指操作系统的整体视觉外观风格,包括配色、阴影、对比度、透明度和光影效果等。自 iOS 13 和 macOS 10.14(Mojave) 起,Apple 引入了 深色模式(Dark Mode),让用户能够选择使用浅色(Light Mode)或深色(Dark Mode),或根据时间自动切换系统主题。
浅色模式(Light Mode): 系统界面和应用程序主要以白色或浅色为背景,深色为前景(如文本和图标),适合大多数环境下的使用,尤其是亮光环境。
深色模式(Dark Mode): 系统界面和应用程序主要以深色为背景,浅色为前景,适用于暗光环境或夜间使用,以减少眼睛疲劳,同时突出内容。
2. 系统主题的特性 #
- 在启用深色模式时,系统会切换通用设计的颜色样式(例如窗口背景、桌面图标、菜单栏等)。
- 开发者可以通过系统提供的 API,自适应用户当前环境,实现自动切换主题。
- 系统主题切换会:
- 动态改变界面颜色。
- 影响 Apple 提供的系统控件,例如按钮、导航栏等。
- 自动调整内容的对比度和字体样式。
3. 开发者如何实现系统主题适配 #
在开发中,我们需要确保应用能够自动适配系统主题,或在特定场景下支持自定义主题。以下分为 SwiftUI 和 UIKit 两大框架,分别讲解如何处理系统主题。
3.1 SwiftUI 中的主题适配 #
(1) 默认支持系统主题 #
SwiftUI 应用中的大部分 UI 默认支持系统主题切换。只需要确保:
- 不使用硬编码的颜色,而是使用系统的 动态颜色(Dynamic Colors)。
- 避免对背景和前景指定固定值。
代码示例:
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("Hello, World!")
.padding()
Button("Press Me") {}
.padding()
}
.background(Color(.systemBackground)) // 自动适配系统主题
}
}
说明:
Color(.systemBackground)
将使用系统动态背景色,浅色模式背景为白色,深色模式背景为黑色。- 系统控件(如
Button
)和字体颜色也会根据主题自动变化。
(2) 强制设置颜色模式(preferredColorScheme
参数)
#
如果需要在某些页面强制应用浅色或深色模式,可以使用 .preferredColorScheme
修饰符。
示例:强制深色模式显示
import SwiftUI
struct DarkModeView: View {
var body: some View {
Text("This View is Always Dark Mode")
.padding()
.preferredColorScheme(.dark) // 强制深色模式
}
}
(3) 检测系统当前主题(colorScheme
环境变量)
#
SwiftUI 提供了 Environment
属性包装器,允许你检测当前的系统主题。
代码示例:检测并响应系统主题
import SwiftUI
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme // 当前的颜色模式 ("light" or "dark")
var body: some View {
VStack {
if colorScheme == .dark {
Text("Dark Mode Enabled")
} else {
Text("Light Mode Enabled")
}
}
.padding()
}
}
3.2 UIKit 中的主题适配 #
(1) 动态颜色(UIColor
和 CGColor
)
#
UIKit 提供了一组动态适配颜色的 API,当系统主题切换时,这些动态颜色会和系统主题保持一致。
常用动态颜色:
UIColor.systemBackground
UIColor.secondarySystemBackground
UIColor.label
UIColor.secondaryLabel
UIColor.systemGray
代码示例:动态颜色使用
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.systemBackground
let label = UILabel()
label.text = "Hello, World!"
label.textColor = UIColor.label // 自动根据系统主题切换
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}
(2) 检测系统外观模式(UITraitCollection
)
#
UIKit 中可以通过 traitCollection
获取当前系统的外观模式。
示例:检测当前主题模式
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.userInterfaceStyle == .dark {
print("Dark Mode")
} else {
print("Light Mode")
}
}
3.3 动态图片资源 #
- 在 Assets.xcassets 文件中,你可以为图片资源设置不同的外观配置(例如深色和浅色模式下的不同图片)。
- 在项目的 Assets 文件中设置「Appearance」为 Any, Light, Dark。
使用动态图片:
Image("DynamicImage")
.resizable()
当系统切换主题时,图片会自动切换到相应的版本。
4. 用户自定义主题实现 #
除了随系统主题切换,很多应用希望提供用户自定义主题功能(例如手动切换深浅模式),这需要保存用户的选择并动态指定视图的外观样式。
以下是如何实现用户自定义主题的示例:
4.1 使用 @AppStorage 持久化用户选择(SwiftUI) #
代码示例:主题选择器
struct ContentView: View {
@AppStorage("userPreferredTheme") var userPreferredTheme: String = "system"
var colorScheme: ColorScheme? {
switch userPreferredTheme {
case "light": return .light
case "dark": return .dark
default: return nil // 跟随系统
}
}
var body: some View {
VStack {
Text("Select Theme")
Picker("", selection: $userPreferredTheme) {
Text("System").tag("system")
Text("Light").tag("light")
Text("Dark").tag("dark")
}
.pickerStyle(SegmentedPickerStyle())
}
.preferredColorScheme(colorScheme)
}
}
4.2 保存用户偏好并手动切换(UIKit) #
UIKit 中可以使用 UserDefaults
保存用户的主题偏好,并根据保存的值设置全局外观。
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let theme = UserDefaults.standard.string(forKey: "themePreference") {
overrideUserInterfaceStyle = (theme == "dark") ? .dark : .light
}
}
func saveThemePreference(_ theme: String) {
UserDefaults.standard.set(theme, forKey: "themePreference")
overrideUserInterfaceStyle = (theme == "dark") ? .dark : .light
}
}
5. 最佳实践 #
5.1 始终使用动态颜色 #
- 避免使用硬编码的颜色(如
.black
或.white
)。 - 使用系统提供的动态颜色(
UIColor
或Color
),以确保在主题切换时界面自动适配。
5.2 提供用户主题选项 #
- 允许用户手动选择浅色/深色模式,这样可以覆盖系统设置(如果业务需求明确)。
5.3 测试界面在不同主题下的表现 #
- 确保在浅色和深色两种模式下,界面都保持良好的可读性和对比度。
- 可以通过
preferredColorScheme
或开发者模拟器调试。
6. 总结 #
系统主题是现代 UI 中的一个重要组成,提供了动态的用户体验能力,而开发者对浅色和深色模式的适配主要关注:
- 使用动态颜色和图片资源替代硬编码颜色。
- 为用户提供个性化主题切换选项。
- 在浅色和深色主题下测试和优化可读性和对比度。
这不仅能提升用户体验,还能为应用带来更广泛的适配能力,让你的应用更符合现代设计要求。