From apple-dev
Use after completing a module, or when the user says 'ui review', 'check UI compliance'. Performs Apple platform SwiftUI UI and interaction compliance review for quality checks. Validates accessibility, state completeness, interaction guards, and platform conventions.
npx claudepluginhub n0rvyn/indie-toolkit --plugin apple-devThis skill uses the workspace's default tool permissions.
Apple platform SwiftUI 代码的 UI + UX 专项审查。在功能模块完成后手动触发。
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Designs, implements, and audits WCAG 2.2 AA accessible UIs for Web (ARIA/HTML5), iOS (SwiftUI traits), and Android (Compose semantics). Audits code for compliance gaps.
Apple platform SwiftUI 代码的 UI + UX 专项审查。在功能模块完成后手动触发。
询问用户或自动识别:
*View.swift、*Screen.swiftreferences/apple-ui-checklist.md 获取代码合规检查项references/ui-design-principles.md §13 检查清单 和 §16 页面构成模板WindowGroup/MenuBarExtra/NSViewRepresentable/#if os(macOS)),额外读取 apple-ui-checklist.md section 12(macOS UI 检查)对每个 UI 文件,检查以下维度:
AppSpacing._4xs/_3xs/_2xs/xs/sm/md/lg/xl/_2xl + AppLayout.marginCompact/marginRegular 而非硬编码)Token 检查:搜索硬编码 .padding(N) 或 .spacing(N),N 不是 8pt 倍数即标记。
💡 如需完整 Token 合规扫描,单独运行
/validate-design-tokens。
/design-review)Color.primary 而非 Color.black)Color(hex:) 应定义在 Design System).secondary on .secondary).opacity() 在深色模式下是否仍可见?.font(.body) 而非 .font(.system(size:))).monospacedDigit()?.accessibilityLabel()?.accessibilityHidden(true)?检查同后缀组件(*Card/*Row/*Cell/*Badge/*Chip/*Tile/*Banner)是否使用一致的布局修饰符。
代码检查:
ExpenseCard → Card)Grep("struct \\w+Card", glob: "*.swift")| 属性 | 搜索模式 | 一致性要求 |
|---|---|---|
| 宽度行为 | .frame(maxWidth: / .frame(width: / 无 frame | 同类必须相同 |
| 内边距 | .padding( | 同方向同值(或同 token) |
| 背景 | .background( | 同颜色/材质类型 |
| 圆角 | .clipShape( / cornerRadius | 同值或同 token |
| 阴影 | .shadow( | 同参数 |
检查项:
启发式规则(区块级 View 宽度):
有 .background() + .overlay(strokeBorder) / .border() 的 View,在垂直布局(VStack / ScrollView / List)中如果缺少 frame(maxWidth: .infinity),标记为 🟡。
.background( 和 .strokeBorder((或 .border()但不含 .frame(maxWidth: 的 View body常见问题:
InsightCard 用 .frame(maxWidth: .infinity) 撑满,ExpenseCard 无 frame modifier 自适应SyncProgressCard 有 background + strokeBorder 但无 frame(maxWidth: .infinity),导致卡片宽度 hug contentProfileRow padding 16pt,SettingsRow padding 12pt*Card 统一使用 .frame(maxWidth: .infinity).padding(AppSpacing.sm).clipShape(.rect(cornerRadius: AppCornerRadius.medium))检查每个异步操作(网络请求、数据库查询)是否处理四态:
| 状态 | 代码特征 |
|---|---|
| Loading | ProgressView() 或 loading 状态变量 |
| Success | 正常内容展示 |
| Error | 错误视图 + 明确下一步 |
| Empty | ContentUnavailableView 或空状态占位 |
检查方法:
// 找到 async 调用
Task { await fetchData() }
// 验证是否有对应的状态处理
@State private var isLoading = false
@State private var error: Error?
// 且在 View 中有条件渲染
常见问题:
检查错误提示是否包含下一步:
// ✅ 好:告诉用户怎么办
.alert("加载失败", isPresented: $showError) {
Button("重试") { Task { await retry() } }
Button("取消", role: .cancel) { }
} message: {
Text("请检查网络连接后重试")
}
// ❌ 坏:只说失败,不说怎么办
.alert("错误", isPresented: $showError) {
Button("确定") { }
}
检查项:
检查是否防止重复触发:
// ✅ 好:提交时禁用按钮
Button("提交") { Task { await submit() } }
.disabled(isSubmitting)
// ❌ 坏:无防护,可重复点击
Button("提交") { Task { await submit() } }
检查项:
.disabled() 防重复?.confirmationDialog() 确认?检查校验是否在合理时机:
// ✅ 好:失焦时校验 + 提交前校验
TextField("Email", text: $email)
.onSubmit { validateEmail() }
.onChange(of: email) { if !email.isEmpty { validateEmail() } }
// ❌ 坏:每输入一个字符就报错
TextField("Email", text: $email)
.onChange(of: email) { validateEmail() } // 输入 "a" 就报 "邮箱格式错误"
检查项:
检查返回后状态是否丢失:
// ✅ 好:使用 @State 或持久化
@State private var scrollPosition: Int?
// ❌ 坏:每次进入都重新加载,丢失滚动位置
.onAppear { loadData() } // 无条件重载
检查项:
.onAppear 无条件重载覆盖用户状态?参考:
apple-ui-checklist.md§10
检查项:
Button 而非 .onTapGesture?
代码检查:搜索 .onTapGesture,检查作用对象是否应该是 Button。.task {} 而非裸 Task {}?
代码检查:搜索 Task { 或 Task.init(不含 .task modifier),检查是否在 View body/onAppear 中。.sheet() modifier?
代码检查:搜索 .sheet(,按 View struct 分组,>1 个则标记。DispatchQueue.main.asyncAfter 做 Sheet 切换?
代码检查:搜索 asyncAfter,检查上下文是否是关闭一个 sheet 后打开另一个。.glassEffect()?
代码检查:搜索 .glassEffect(,检查作用对象是否在 View body/List/ScrollView 的内容层。.shadow()?
代码检查:搜索 .shadow(,检查前方是否有 .glassEffect(。presentationBackground()?
代码检查:搜索 presentationBackground,在 iOS 26 target 上标记。仅当 Step 2 判定为 macOS 项目时执行。参考
apple-ui-checklist.mdsection 12。
Window 行为:
.frame(minWidth:minHeight:)?WindowGroup / Window / Settings 场景选择是否正确?Toolbar & Menu:
键盘导航:
.keyboardShortcut() 绑定?Sidebar 导航:
NavigationSplitView 做一级导航(而非 TabBar)?鼠标交互:
.onHover 状态?.help("...") tooltip?以下项目 Claude 无法通过代码验证,需要人工运行后确认。根据代码分析生成针对性问题。
基于代码分析识别的入口和流程,生成:
请人工验证以下任务流:
- [ ] 从 [入口A] 到 [目标B] 是否可顺利完成?
- [ ] 每一步的下一步操作是否明确?
- [ ] 是否有"死路"(无法返回或继续)?
请人工验证:
- [ ] 页面主操作是否一眼可见?
- [ ] 主次按钮是否有明显区分?
- [ ] 信息层级是否清晰(标题 > 正文 > 辅助)?
请人工验证:
- [ ] 页面切换是否流畅?
- [ ] 是否有掉帧或卡顿?
- [ ] 动画是否有助于理解状态变化?
代码检查提示:if-else 视图切换需用 Group {} 包装后加 .transition() + .animation()。
请人工验证:
- [ ] 冷启动后多久可以开始操作?
- [ ] 是否有骨架屏或占位减少等待感?
- [ ] 首屏加载失败时用户是否知道发生了什么?
## UI + UX Review Report
### 检查范围
- [文件列表]
### Part A: 视觉规范
#### 🔴 必须修复
- [file:line] 问题描述
建议:具体修复方案
#### 🟡 建议修复
- [file:line] 问题描述
建议:具体修复方案
### Part B: 交互完整性
#### 🔴 必须修复
- [file:line] 问题描述
建议:具体修复方案
验收:[可测试的验收标准]
#### 🟡 建议修复
- [file:line] 问题描述
建议:具体修复方案
### Part C: 人工验证清单
基于代码分析,建议验证以下项目:
- [ ] [具体验证项1]
- [ ] [具体验证项2]
...
### 总结
- 检查文件数:N
- 视觉规范问题:N(必须修复 X,建议修复 Y)
- 交互完整性问题:N(必须修复 X,建议修复 Y)
- 人工验证项:N
| 级别 | 定义 | 示例 |
|---|---|---|
| 🔴 必须修复 | 阻断任务或造成困惑 | 无 loading 态、错误无提示、按钮可重复点击 |
| 🟡 建议修复 | 影响体验但不阻断 | 硬编码间距、缺少空状态 |
| ⚪ 通过 | 符合规范 | - |
报告末尾附加:
---
💡 代码合规检查完成。如需进一步审查视觉层级、色彩策略、间距节奏等设计质量,请运行 `/design-review`。