ios-projects/AIStudyApp/docs/样式规范.md
WangDL 7066200b7b feat: MVVM 架构、全套 UI 页面、浅深色主题、本地持久化、等待名单、AI 动效
- 架构层: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>
2026-05-10 22:22:50 +08:00

18 KiB
Raw Blame History

知习 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 同 brandCTA 语义
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 图标

使用原则

  • 卡片统一 1420
  • 按钮统 1218
  • 输入框 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 间距   = 1220
ScrollView bottom   = 120有 TabBar/ 80100子页面

五、尺寸

// 按钮
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 导航/布局

ZXTabBarContentView.swift:58 5 个 tabAI / 知识库 / 学习 / 分析 / 我的),选中态紫色高亮 + 圆形背景扩散。

ZXTabBar(active: $selectedTab)

ZXBackHeaderDailyThinkingPage.swift:52 子页面顶部返回栏,含标题、副标题、可选的右侧按钮。

ZXBackHeader(title: "标题", subtitle: "副标题") { trailingView }
ZXBackHeader(title: "标题", subtitle: nil, onBack: customBackAction) { ... }

7.2 按钮

ZXIconBtnContentView.swift:100 标准 36pt 圆形图标按钮,可切换品牌渐变样式。

ZXIconBtn(icon: "bell", size: 36) { action }
ZXIconBtn(icon: "plus", size: 36, branded: true) { action }  // 品牌渐变底

ZXOutlineBtnDailyThinkingPage.swift:167 44pt 高描边文字按钮。

ZXOutlineBtn(text: "深入提问")

7.3 列表/卡片行

ZXCardRowLibrarySubpages.swift:40 带 emoji 图标、标题、描述、状态标签的标准列表行。

ZXCardRow(emoji: "📝", title: "标题", desc: "描述", status: "已掌握", c: .zxGreen)

ZXImportOptionLibrarySubpages.swift:93 带大图标 + 标题描述的导入选项行。

ZXProfileMenuRowProfileView.swift:58 Profile 页菜单行emoji + 标题 + 描述 + 箭头。

ReviewTaskRowReviewPlanView.swift:82 复习任务行,含完成勾选 + 复习类型标签 + 播放按钮。

ZXAIInteractionRowAIHomeView.swift:138 AI 互动记录行,含标签 + 时间 + 分数。

7.4 数据展示

ZXScoreBoxContentView.swift:50 36pt 方形分数格。

ZXScoreBox(score: 82, bg: .zxGreenBG(0.15), fg: .zxGreen)

ZXStatBadgeAnalysisHomeView.swift:74 统计徽章,图标 + 数值 + 标签 + 趋势。

ZXWeakRowAnalysisHomeView.swift:91 薄弱知识点行,分数 + 标题 + 库名 + 优先级。

ZXAchievementBadgeProfileView.swift:61 成就徽章emoji + 标签。

ZXProfileStatProfileView.swift:55 Profile 页三栏统计数字。

ZXChartViewAnalysisHomeView.swift:117 折线图(掌握度趋势)。

7.5 输入

ZXAIInputBarContentView.swift:26 AI 对话输入栏,含 sparkles 图标 + 文本框 + 麦克风 + 发送按钮。

7.6 标签

ZXChipLibrarySubpages.swift:74 Capsule 标签,彩色文字 + 半透明底色。

复习类型标签ReviewTaskRow.swift:129 4 种:间隔重复(紫) / 费曼(accent) / 回忆(橙) / 薄弱(黄)。

7.7 卡片装饰

ZXQuickActionAIHomeView.swift:132 72pt 高快捷操作按钮emoji + 文字。

ZLibraryCardLibraryHomeView.swift:32 知识库卡片,顶部渐变色条 + emoji + 名称 + 进度 + 标签。

7.8 状态组件

ZXLoadingViewShared/Components/ZXLoadingView.swift 全屏加载指示器,紫色 ProgressView + "加载中…" 文字。

ZXShimmerListShared/Components/ZXLoadingView.swift 骨架屏列表,传入 count 生成占位卡片。

ZXErrorViewShared/Components/ZXErrorView.swift 全屏错误状态,黄色三角图标 + 消息 + 可选重试按钮。

ZXErrorBannerShared/Components/ZXErrorView.swift 内联错误横幅,黄色背景 + 消息 + 关闭按钮。

ZXEmptyViewShared/Components/ZXEmptyView.swift 空状态视图,支持图标 + 标题 + 副标题 + 可选操作按钮。

7.9 其他

FeatureRowShared/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
  • 卡片间距 1220pt
  • 内容区底部留白至少 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