SwiftUI 设计令牌与主题系统(生产规模)

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

Source: Dev.to

随着 SwiftUI 应用的规模扩大,UI 的一致性变得脆弱。你会开始看到:

  • 略有差异的间距值
  • 不统一的圆角半径
  • 随处硬编码的随机颜色
  • 暗黑模式的 bug
  • 可访问性问题
  • 痛苦的品牌重塑工作

解决方案是 设计令牌(design tokens)——所有视觉决策的唯一真相来源。本文展示了如何在 SwiftUI 中构建一个 可用于生产的设计令牌与主题系统,并实现干净的可扩展性。

🧠 设计令牌是什么?

设计令牌是 具名的、语义化的值,而不是原始数字。

错误示例

.padding(12)
.cornerRadius(16)
.foregroundColor(.blue)

正确示例

.padding(.md)
.cornerRadius(.card)
.foregroundStyle(.accent)

令牌表达意图,而非实现细节。

📦 1. 核心令牌类别

一个完整的系统通常包括:

  • 间距(Spacing)
  • 圆角(Radius)
  • 排版(Typography)
  • 颜色(Colors)
  • 阴影/层次(Elevation)
  • 动画(Animation)
  • 不透明度(Opacity)

我们将逐一清晰定义。

📏 2. 间距令牌

enum Spacing {
    static let xs: CGFloat = 4
    static let sm: CGFloat = 8
    static let md: CGFloat = 16
    static let lg: CGFloat = 24
    static let xl: CGFloat = 32
}

使用方式

.padding(Spacing.md)

🔲 3. 圆角令牌

enum Radius {
    static let sm: CGFloat = 6
    static let md: CGFloat = 12
    static let lg: CGFloat = 20
    static let card: CGFloat = 16
}

🎨 4. 颜色令牌(语义化,而非视觉)

绝不要这样写:

Color.blue

而应该这样:

enum AppColor {
    static let background = Color("Background")
    static let surface = Color("Surface")
    static let accent = Color("Accent")
    static let textPrimary = Color("TextPrimary")
    static let textSecondary = Color("TextSecondary")
}

Assets 负责处理亮/暗模式、可访问性对比度以及品牌变更。

🔤 5. 排版令牌

enum AppFont {
    static let title = Font.system(size: 28, weight: .bold)
    static let headline = Font.system(size: 20, weight: .semibold)
    static let body = Font.system(size: 16)
    static let caption = Font.system(size: 13)
}

使用方式

Text("Title")
    .font(AppFont.title)

🧊 6. 阴影与材质令牌

enum Elevation {
    static let card = CGFloat(4)
    static let modal = CGFloat(12)
}
.background(.ultraThinMaterial)
.shadow(radius: Elevation.card)

🕺 7. 动画令牌

enum Motion {
    static let fast = Animation.easeOut(duration: 0.15)
    static let standard = Animation.easeInOut(duration: 0.25)
    static let slow = Animation.spring(response: 0.45)
}

🌗 8. 主题容器

创建一个主题模型:

struct AppTheme {
    let colors: AppColor.Type
    let spacing: Spacing.Type
    let radius: Radius.Type
}

通过环境注入:

.environment(\.theme, currentTheme)

🔁 9. 支持多主题

enum ThemeKind {
    case light
    case dark
    case highContrast
}

根据以下条件动态切换:

  • 系统外观
  • 可访问性设置
  • 用户偏好
  • A/B 测试

🧪 10. 预览变得强大

#Preview("Dark") {
    ContentView()
        .environment(\.theme, .dark)
}

设计验证瞬间完成。

🚀 最后思考

设计令牌系统为你带来:

  • 一致性
  • 可访问性
  • 更快的迭代
  • 更安全的重构
  • 轻松的品牌重塑
  • 更简洁的代码
  • 更开心的设计师

一旦采用令牌,你将不再回头。

Back to Blog

相关文章

阅读更多 »

SwiftUI 焦点系统 & 键盘内部

!Sebastien Lato https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads...

SwiftUI 可访问性内部

可访问性是一棵平行视图树 SwiftUI 构建了两棵树: - 可视视图树 - 可访问性树 它们相关——但并不相同。 单个…

SwiftUI 手势系统内部

markdown !Sebastien Latohttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%...

SwiftUI 视图差分与调和

SwiftUI 并不会“重新绘制屏幕”。它对视图树进行差异比较。如果你不了解 SwiftUI 如何决定哪些发生了变化、哪些保持不变,你会看到不必要的…