- 架构层:ViewModel/ObservableObject、Service/Repository、网络层 APIClient/APIEndpoint/APIError - 设计系统:Color(light:dark:) 自适应 28 色 Token、ColorSchemeManager 深浅色切换 - 全页面:AI 对话/反馈/回忆/薄弱点、知识库 CRUD、学习工作台、复习计划、学习分析、个人中心/设置 - 登录与引导:Sign in with Apple、AppSession 状态管理、引导流程、演示模式 - 本地持久化:FileCache + PersistenceController(学习任务/复习任务/学习记录) - 本地化:zh-Hans Localizable.strings ~120 条、ZXStrings 程序化引用、LanguageManager - 组件库:ZXTabBar/ZXBackHeader/ZXSTaskRow/ZXChartView/ZXTypingIndicator 等 22 个共享组件 - 等待名单:WaitlistView 邮箱收集表单 - 动效:ZXTypingIndicator AI 打字动画、ZXShimmerModifier 骨架屏 - 测试:StudyHomeViewModel/AIChatViewModel/ReviewPlanViewModel/FileCache 共 28 条 - Dynamic Type 支持 + 范围限制 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
18 KiB
知习 iOS 样式规范
基于现有 DesignTokens 与实际页面中反复出现的 UI 模式,归纳形成本规范。 后续创建新页面时,优先从本文档引用的 token 和组件中选择,保持一致的设计语言。
一、色彩系统
所有颜色定义在 Core/DesignSystem/DesignTokens.swift,命名前缀 zx(知习)。
1.1 背景
| Token | 色值 | 用途 |
|---|---|---|
zxBg0 |
#0F0F1A |
页面基底(与 zxBg1 组成 page 渐变) |
zxBg1 |
#12122A |
page 渐变的第二色 |
zxBg2 |
#0A0A14 |
手机外壳装饰用,极少使用 |
zxBgSplash |
#0D0D20 |
启动页专用 |
1.2 文字
所有文字色基于 #F0F0FF(近白紫调)变化透明度:
| Token | 透明度 | 用途 |
|---|---|---|
zxF0 |
100% | 标题、正文高亮 |
zxF007 |
70% | 次重要正文 |
zxF006 |
60% | — |
zxF05 |
50% | 次要信息 |
zxF0045 |
45% | — |
zxF04 |
40% | 辅助描述 |
zxF035 |
35% | 弱标签、灰色字段名 |
zxF03 |
30% | 占位符级别 |
zxF02 |
20% | 极弱(如未选中图标边框) |
1.3 品牌/语义色
| Token | 色值 | 含义 |
|---|---|---|
zxPurple |
#7C6EFA |
主品牌,选中态、标签、进度 |
zxAccent |
#A78BFA |
次要品牌,AI 相关 |
zxOrange |
#F97316 |
热度/连续天数/回忆 |
zxTeal |
#2DD4BF |
语言/词汇 |
zxCyan |
#4ECDC4 |
进度条渐变 |
zxGreen |
#34D399 |
已掌握、成功 |
zxYellow |
#F59E0B |
薄弱/警告/待复习 |
zxRed |
#EF4444 |
错误/高优先级 |
彩色半透明背景(用于标签、badge 底衬):
zxPurpleBG(0.12) // 紫色 12% 透明
zxOrangeBG(0.10) // 橙色 10% 透明
zxGreenBG(0.15) // 绿色 15% 透明
zxYellowBG(0.15) // 黄色 15% 透明
zxTealBG(0.10) // 青色 10% 透明
zxRedBG(0.15) // 红色 15% 透明
1.4 边框/分割线
| Token | 透明度 | 用途 |
|---|---|---|
zxBorder015 |
15% | 较明显边框 |
zxBorder01 |
10% | 标准边框、虚线框 |
zxBorder008 |
8% | 通用卡片边框 |
zxBorder006 |
6% | 弱边框、卡片分隔 |
zxBorder004 |
4% | 极弱边框 |
1.5 填充(半透明叠层)
| Token | 透明度 | 用途 |
|---|---|---|
zxFill01 |
10% | 图表柱状 |
zxFill008 |
8% | 进度条底色 |
zxFill006 |
6% | 列表图标底衬 |
zxFill005 |
5% | 按钮/选中行底衬 |
zxFill004 |
4% | 输入框/面板底色 |
zxFill003 |
3% | 卡片底色 |
二、渐变
所有渐变定义在 ZXGradient enum。
| 渐变 | 颜色 | 方向 | 用途 |
|---|---|---|---|
page |
#0F0F1A → #12122A |
top→bottom | 所有主页面背景 |
splash |
#0D0D20 → #0F0F1A → #130D20 |
top→bottom | 启动页背景 |
brand |
#7C6EFA → #F97316 |
topLeading→bottomTrailing | CTA 按钮、播放按钮 |
brandPurple |
#7C6EFA → #9B8BFF |
leading→trailing | 发送按钮、AI 气泡 |
ctaButton |
#7C6EFA → #F97316 |
topLeading→bottomTrailing | 同 brand,CTA 语义 |
ctaPurple |
#7C6EFA → #9B8BFF |
topLeading→bottomTrailing | 紫色 CTA(创建/保存/提交) |
progressBar |
#7C6EFA → #4ECDC4 |
leading→trailing | 进度条 |
thinkingCard |
#7C6EFA 8% → #F97316 4% |
topLeading→bottomTrailing | 思考卡片 |
progressCard |
#7C6EFA 10% → #F97316 5% |
topLeading→bottomTrailing | 进度卡片 |
feedbackScore |
#7C6EFA 12% → #34D399 6% |
topLeading→bottomTrailing | 反馈评分卡片 |
profileCard |
#7C6EFA 15% → #F97316 8% |
topLeading→bottomTrailing | 个人页卡片 |
三、圆角
ZXRadius.xs = 2 // 进度指示器小圆点
ZXRadius.sm = 8 // 小图标
ZXRadius.md = 10 // 标准图标按钮
ZXRadius.lg = 12 // 标签/徽章
ZXRadius.xl = 14 // 卡片/输入框/行
ZXRadius.xl2 = 16 // 大卡片/对话框
ZXRadius.xl3 = 20 // 主要面板
ZXRadius.button = 12 // 标准按钮
ZXRadius.buttonLg = 18 // 大按钮(CTA)
ZXRadius.icon = 10 // 小图标
ZXRadius.iconLg = 12 // 中图标
ZXRadius.avatar = 13 // 头像/emoji 图标
使用原则:
- 卡片统一
14–20 - 按钮统
12–18 - 输入框
14 - 标签
Capsule()(自动全圆角)
四、间距
ZXSpacing.ss = 2 // 字间距/tracking 用
ZXSpacing.xs = 4
ZXSpacing.sm = 6
ZXSpacing.md = 8 // 卡片内元素间距
ZXSpacing.lg = 10
ZXSpacing.xl = 12 // 行内元素间距
ZXSpacing.xl2 = 14
ZXSpacing.xl3 = 16 // 卡片间距
ZXSpacing.xl4 = 20 // 页面水平内边距
ZXSpacing.xl5 = 24
ZXSpacing.xl6 = 28
// 专用
ZXSpacing.pageHPadding = 20 // 所有页面两侧统一留白
ZXSpacing.statusBarH = 44 // 状态栏 + Dynamic Island
ZXSpacing.tabBarH = 83 // 底部 TabBar 总高
ZXSpacing.homeIndicatorH = 34 // Home Indicator
页面结构公式:
header top padding = statusBarH + 16
每个 section 间距 = 12–20
ScrollView bottom = 120(有 TabBar)/ 80–100(子页面)
五、尺寸
// 按钮
ZXSize.iconBtn = 36 // 图标按钮(ZXIconBtn 默认)
ZXSize.buttonH = 42 // 标准按钮高
ZXSize.buttonLgH = 52 // 大按钮高
ZXSize.buttonXlH = 56 // CTA 按钮高
ZXSize.sendBtn = 30 // 发送按钮
// 图标
ZXSize.iconSm = 14
ZXSize.iconMd = 16
ZXSize.iconLg = 18
ZXSize.tabIcon = 22 // TabBar 图标
ZXSize.listIcon = 40 // 列表图标
ZXSize.libraryIcon = 44 // 知识库卡片图标
// 头像
ZXSize.avatarSm = 36
ZXSize.avatarMd = 64
ZXSize.avatarLg = 80
// 其他
ZXSize.quickActionH = 72 // 快捷操作高度
ZXSize.inputH = 44 // 输入框高度
ZXSize.progressH = 5 // 进度条高度
ZXSize.scoreBox = 36 // 分数方块
ZXSize.weakBox = 40 // 薄弱点分数方块
ZXSize.topBar = 3 // 顶部装饰条
ZXSize.searchIconBtn = 36 // 搜索图标按钮
六、字体层级
// 使用方式: .font(.system(size: ZXFont.xxx.size, weight: ZXFont.xxx.weight))
titleLarge // 22pt, heavy, -0.5 → 页面主标题
titleMedium // 20pt, heavy, -0.4 → 二级标题
sectionTitle // 15pt, bold → 区域标题
subsectionTitle // 14pt, bold → 子标题
body // 13pt, semibold, 1.4 → 正文
bodySmall // 12pt, medium → 辅助信息
caption // 10pt, bold → 标签加粗
captionSmall // 10pt, regular → 标签常规
labelXs // 9pt, regular → 最小标签
score // 12pt, heavy → 分数
scoreLarge // 22pt, heavy, 1 → 大分数
date // 12pt, medium → 日期
description // 12pt, regular, 0.4 → 描述文字
实际页面中常用的内联声明(可直接使用,也可用 ZXFont 引用):
- 页面大标题:
.font(.system(size: 22, weight: .heavy)).tracking(-0.5).foregroundColor(.zxF0) - 区域标题:
.font(.system(size: 15, weight: .bold)).foregroundColor(.zxF0) - 卡片标题:
.font(.system(size: 13, weight: .semibold)).foregroundColor(.zxF0) - 辅助文字:
.font(.system(size: 12)).foregroundColor(.zxF04) - 标签文字:
.font(.system(size: 10, weight: .semibold)) - 大数值:
.font(.system(size: 26, weight: .black))
七、共享组件目录
以下组件散落在各页面文件中,新页面应直接复用,禁止重复实现。
7.1 导航/布局
ZXTabBar(ContentView.swift:58)
5 个 tab(AI / 知识库 / 学习 / 分析 / 我的),选中态紫色高亮 + 圆形背景扩散。
ZXTabBar(active: $selectedTab)
ZXBackHeader(DailyThinkingPage.swift:52)
子页面顶部返回栏,含标题、副标题、可选的右侧按钮。
ZXBackHeader(title: "标题", subtitle: "副标题") { trailingView }
ZXBackHeader(title: "标题", subtitle: nil, onBack: customBackAction) { ... }
7.2 按钮
ZXIconBtn(ContentView.swift:100)
标准 36pt 圆形图标按钮,可切换品牌渐变样式。
ZXIconBtn(icon: "bell", size: 36) { action }
ZXIconBtn(icon: "plus", size: 36, branded: true) { action } // 品牌渐变底
ZXOutlineBtn(DailyThinkingPage.swift:167)
44pt 高描边文字按钮。
ZXOutlineBtn(text: "深入提问")
7.3 列表/卡片行
ZXCardRow(LibrarySubpages.swift:40)
带 emoji 图标、标题、描述、状态标签的标准列表行。
ZXCardRow(emoji: "📝", title: "标题", desc: "描述", status: "已掌握", c: .zxGreen)
ZXImportOption(LibrarySubpages.swift:93)
带大图标 + 标题描述的导入选项行。
ZXProfileMenuRow(ProfileView.swift:58)
Profile 页菜单行,emoji + 标题 + 描述 + 箭头。
ReviewTaskRow(ReviewPlanView.swift:82)
复习任务行,含完成勾选 + 复习类型标签 + 播放按钮。
ZXAIInteractionRow(AIHomeView.swift:138)
AI 互动记录行,含标签 + 时间 + 分数。
7.4 数据展示
ZXScoreBox(ContentView.swift:50)
36pt 方形分数格。
ZXScoreBox(score: 82, bg: .zxGreenBG(0.15), fg: .zxGreen)
ZXStatBadge(AnalysisHomeView.swift:74)
统计徽章,图标 + 数值 + 标签 + 趋势。
ZXWeakRow(AnalysisHomeView.swift:91)
薄弱知识点行,分数 + 标题 + 库名 + 优先级。
ZXAchievementBadge(ProfileView.swift:61)
成就徽章,emoji + 标签。
ZXProfileStat(ProfileView.swift:55)
Profile 页三栏统计数字。
ZXChartView(AnalysisHomeView.swift:117)
折线图(掌握度趋势)。
7.5 输入
ZXAIInputBar(ContentView.swift:26)
AI 对话输入栏,含 sparkles 图标 + 文本框 + 麦克风 + 发送按钮。
7.6 标签
ZXChip(LibrarySubpages.swift:74)
Capsule 标签,彩色文字 + 半透明底色。
复习类型标签(ReviewTaskRow.swift:129)
4 种:间隔重复(紫) / 费曼(accent) / 回忆(橙) / 薄弱(黄)。
7.7 卡片装饰
ZXQuickAction(AIHomeView.swift:132)
72pt 高快捷操作按钮,emoji + 文字。
ZLibraryCard(LibraryHomeView.swift:32)
知识库卡片,顶部渐变色条 + emoji + 名称 + 进度 + 标签。
7.8 状态组件
ZXLoadingView(Shared/Components/ZXLoadingView.swift)
全屏加载指示器,紫色 ProgressView + "加载中…" 文字。
ZXShimmerList(Shared/Components/ZXLoadingView.swift)
骨架屏列表,传入 count 生成占位卡片。
ZXErrorView(Shared/Components/ZXErrorView.swift)
全屏错误状态,黄色三角图标 + 消息 + 可选重试按钮。
ZXErrorBanner(Shared/Components/ZXErrorView.swift)
内联错误横幅,黄色背景 + 消息 + 关闭按钮。
ZXEmptyView(Shared/Components/ZXEmptyView.swift)
空状态视图,支持图标 + 标题 + 副标题 + 可选操作按钮。
7.9 其他
FeatureRow(Shared/Components/FeatureRow.swift)
Welcome 页功能介绍行。
八、页面布局模式
8.1 主 Tab 页(有底部 TabBar)
struct SomeHomeView: View {
var body: some View {
ZStack {
ZXGradient.page.ignoresSafeArea() // ① 背景
VStack(spacing: 0) {
// ② Header
HStack {
VStack(alignment: .leading, spacing: 2) {
Text("副标题").font(.system(size: 12)).foregroundColor(.zxF04)
Text("主标题").font(.system(size: 22, weight: .heavy))
.foregroundColor(.zxF0).tracking(-0.5)
}
Spacer()
// 右侧按钮/状态
}
.padding(.horizontal, 20)
.padding(.top, ZXSpacing.statusBarH + 16)
.padding(.bottom, 12)
// ③ 可滚动内容
ScrollView {
VStack(spacing: 16) {
// 卡片/列表...
}
.padding(.horizontal, 20)
.padding(.bottom, 120) // 为 TabBar 留空间
}
.scrollIndicators(.hidden)
}
}
.navigationBarHidden(true)
.preferredColorScheme(.dark)
}
}
8.2 子页面(有返回按钮,无 TabBar)
struct SomeDetailPage: View {
var body: some View {
ZStack {
Color.zxBg0.ignoresSafeArea() // 纯色(非渐变)
VStack(spacing: 0) {
ZXBackHeader(title: "标题", subtitle: "副标题") {
// 右侧按钮
}
ScrollView {
VStack(spacing: 16) {
// 内容
}
.padding(.horizontal, 20)
.padding(.bottom, 80)
}
.scrollIndicators(.hidden)
}
}
.navigationBarHidden(true)
}
}
8.3 卡片通用写法
VStack(alignment: .leading, spacing: 12) {
// 卡片内容
}
.padding(16)
.background(Color.zxFill003) // 底色
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color.zxBorder006, lineWidth: 1) // 边框
)
.clipShape(RoundedRectangle(cornerRadius: 16)) // 裁剪
渐变背景卡片把 .background(Color.zxFill003) 换成对应的 ZXGradient.xxx。
8.4 输入框通用写法
TextField("占位文字", text: $text)
.font(.system(size: 14))
.tint(.zxPurple)
.padding(.horizontal, 16)
.frame(height: 52)
.background(Color.zxFill004)
.clipShape(RoundedRectangle(cornerRadius: 14))
.overlay(
RoundedRectangle(cornerRadius: 14)
.stroke(Color.zxBorder008, lineWidth: 1)
)
8.5 状态标签(Capsule 形)
Text("标签文字")
.font(.system(size: 10, weight: .semibold))
.foregroundColor(semanticColor)
.padding(.horizontal, 8)
.padding(.vertical, 2)
.background(semanticColor.opacity(0.12))
.clipShape(Capsule())
九、设计决策与约束
9.1 全局
- 强制深色模式:
.preferredColorScheme(.dark) - 所有页面
navigationBarHidden(true),使用自建导航 - 禁止使用系统默认蓝色、默认圆角、默认间距
9.2 颜色
- 文字统一用
#F0F0FF加透明度,不要用Color.white - 不要直接写
Color(hex: ...)内联,优先用现有 token;确需新色值先加 token - 语义色不要混用——紫色是品牌/AI,橙色是热度/连续,绿色是完成,黄色是警告
9.3 字体
- 不使用系统默认字体大小(如
.title、.headline),一律显式.system(size:weight:) - 标题统一 tracking 负值(
-0.5或-0.4) - 中文内容避免使用
.bold以下的极细字体
9.4 布局
- 页面水平留白统一
20pt - 卡片间距
12–20pt - 内容区底部留白至少
80pt(子页面)或120pt(有 TabBar) - 所有 ScrollView 隐藏指示器:
.scrollIndicators(.hidden)
9.5 组件
- 优先复用第七节的共享组件,不要内联重复 UI
- 新组件如通用性足够,应抽到
Shared/目录
十、文件引用索引
| 规范项 | 定义文件 |
|---|---|
| 颜色/渐变/圆角/间距/尺寸/字体 | Core/DesignSystem/DesignTokens.swift |
| ZXTabBar | Shared/Components/ZXTabBar.swift |
| ZXIconBtn | Shared/Components/ZXIconBtn.swift |
| ZXScoreBox | Shared/Components/ZXScoreBox.swift |
| ZXAIInputBar | Shared/Components/ZXAIInputBar.swift |
| ZXBackHeader | Shared/Components/ZXBackHeader.swift |
| ZXOutlineBtn | Shared/Components/ZXOutlineBtn.swift |
| ZXQuickAction | Shared/Components/ZXQuickAction.swift |
| ZXAIInteractionRow | Shared/Components/ZXAIInteractionRow.swift |
| ZXCardRow | Shared/Components/ZXCardRow.swift |
| ZXChip | Shared/Components/ZXChip.swift |
| ZXImportOption | Shared/Components/ZXImportOption.swift |
| ZXWeakRow | Shared/Components/ZXWeakRow.swift |
| ZXStatBadge | Shared/Components/ZXStatBadge.swift |
| ZXProfileMenuRow | Shared/Components/ZXProfileMenuRow.swift |
| ZXProfileStat | Shared/Components/ZXProfileStat.swift |
| ZXAchievementBadge | Shared/Components/ZXAchievementBadge.swift |
| ZXChartView | Shared/Components/ZXChartView.swift |
| ZXSTaskRow + ZXSTask | Shared/Components/ZXSTaskRow.swift |
| FeatureRow | Shared/Components/FeatureRow.swift |
| ReviewTaskRow | Shared/Components/ReviewTaskRow.swift |
| ZXLoadingView / ZXShimmerList | Shared/Components/ZXLoadingView.swift |
| ZXErrorView / ZXErrorBanner | Shared/Components/ZXErrorView.swift |
| ZXEmptyView | Shared/Components/ZXEmptyView.swift |
| ZXLibraryCard | Features/Library/LibraryHomeView.swift |
| AIHomeView | Features/AI/AIHomeView.swift |
| DailyThinkingPage | Features/AI/DailyThinkingPage.swift |
| RecallTestPage | Features/AI/RecallTestPage.swift |
| WeakPointsPage | Features/AI/WeakPointsPage.swift |
| AIFeedbackPageView | Features/AI/AIFeedbackPage.swift |
| AIChatPage | Features/AI/AIChatPage.swift |
| LibraryHomeView | Features/Library/LibraryHomeView.swift |
| CreateLibraryPage | Features/Library/CreateLibraryPage.swift |
| LibraryDetailPage | Features/Library/LibraryDetailPage.swift |
| AddKnowledgePage | Features/Library/AddKnowledgePage.swift |
| KnowledgeDetailPage | Features/Library/KnowledgeDetailPage.swift |
| ImportPage | Features/Library/ImportPage.swift |
| EditKnowledgePage | Features/Library/EditKnowledgePage.swift |
| AnalysisHomeView | Features/Analysis/AnalysisHomeView.swift |
| ProfileView | Features/Profile/ProfileView.swift |
| ReviewPlanView | Features/Review/ReviewPlanView.swift |
| StudyHomeView | Features/Study/StudyHomeView.swift |
| SplashPage | Features/Onboarding/SplashPage.swift |
| WelcomePage | Features/Onboarding/WelcomePage.swift |
| OnboardingPage | Features/Onboarding/OnboardingPage.swift |
| GoalSetupPage | Features/Onboarding/GoalSetupPage.swift |
| AppRootView / OnboardingFlowView | AIStudyAppApp.swift |
| LoginView | Features/Auth/Views/LoginView.swift |