关于 android-ux
面向 Android 开发者的参考技能,用于审查现有界面是否符合 Material Design 3,并处理较少见的平台行为。内容涵盖折叠屏、对比度、动效、无障碍和设计令牌。
主要功能
- 01Material 3 合规性审查
- 02折叠屏姿态布局指南
- 03应用内对比度方案指南
- 04动效令牌与减少动效
- 05无障碍与主题检查
- 06违规项快速 grep 检查
适用场景
- 01发布前审查现有界面
- 02适配折叠屏姿态布局
- 03检查动效和对比度表现
- 04查找硬编码样式和 Material 2 导入
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rcosteira79/ android-skills --skill android-ux安装后在 Claude Code 中输入/android-ux确认已加载。
详细介绍
Android UX
本参考介绍了不那么显而易见的平台事实,以及如何审查现有屏幕的 M3 合规性,而不是介绍构建符合 M3 规范的 UI 的基础知识。
不那么显而易见的平台事实
可折叠设备的使用姿态
可折叠设备除了窗口尺寸类别外,还引入了其他使用姿态。使用 WindowInfoTracker + FoldingFeature(Jetpack WindowManager)检测,并且绝不要将交互内容或关键信息放在铰链两侧。
| 使用姿态 | 检测方式 | 布局行为 |
|---|---|---|
| 展开(摊平) | 无折叠特征 | 按宽度视为 Medium/Expanded |
| 半展开、水平折叠(桌面模式) | HALF_OPENED + Orientation.HORIZONTAL | 内容置于上半部分,控件置于下半部分 |
| 半展开、垂直折叠(书本模式) | HALF_OPENED + Orientation.VERTICAL | 列表置于左侧,详情置于右侧 |
| 折叠(封面屏幕) | — | 视为 Compact |
@Composable
fun FoldAwareLayout() {
val context = LocalContext.current
val layoutInfo by WindowInfoTracker.getOrCreate(context)
.windowLayoutInfo(context) // accepts @UiContext — Activity, InputMethodService, or createWindowContext()
.collectAsStateWithLifecycle(initialValue = WindowLayoutInfo(emptyList()))
val fold = layoutInfo.displayFeatures.filterIsInstance<FoldingFeature>().firstOrNull()
when {
fold?.state == FoldingFeature.State.HALF_OPENED ->
if (fold.orientation == FoldingFeature.Orientation.HORIZONTAL) TabletopLayout() else BookLayout()
else -> StandardAdaptiveLayout() // by window size class
}
}
M3 对比度级别(用户可控对比度)
Compose 的 dynamicLightColorScheme / dynamicDarkColorScheme 会自动读取系统对比度设置(SDK 34+),且没有对比度参数。若要提供应用内对比度控制(标准 0.0 / 中 0.5 / 高 1.0 色调距离),请使用 Hct + SchemeContent 构建配色方案:
// com.google.android.material:material (MDC-Android), package com.google.android.material.color.utilities
// Marked @RestrictTo(LIBRARY_GROUP) — internal API, may change between versions; re-check on version bumps.
val hct = Hct.fromInt(0xFF6750A4.toInt())
val scheme = SchemeContent(hct, /* isDark = */ false, /* contrastLevel = */ 1.0)
val colorScheme = lightColorScheme(
primary = Color(scheme.primary),
onPrimary = Color(scheme.onPrimary),
// ... map remaining roles
)
对于多平台项目或稳定的公共 API,com.materialkolor:material-color-utilities 是一种 KMP 替代方案。
动效:时长令牌 + 减少动效
将 M3 的时长梯度与缓动曲线搭配使用(short* → FastOutSlowIn;medium* → Emphasized(De/Ac)celerate;long*/extraLong* → Emphasized),而不是使用任意毫秒数。可用时优先采用 MotionScheme(Compose M3 1.4+);否则在主题中将时长统一维护于唯一来源。
| 令牌组 | 范围 | 典型用途 |
|---|---|---|
short1…short4 | 50–200ms | 微交互、状态变化(涟漪、选择、开关) |
medium1…medium4 | 250–400ms | 标准转场(屏幕进入/退出、展开、显示) |
long1…long4 | 450–600ms | 容器变换、大型表面之间的淡入淡出 |
extraLong1…extraLong4 | 700–1000ms | 平板/可折叠设备上的共享元素 / 主视觉转场 |
动画必须可中断,且绝不能阻塞输入。尊重减少动效设置——Compose 没有内置的 LocalReducedMotion,因此请读取 ANIMATOR_DURATION_SCALE 并提供一个:
val LocalReducedMotion = staticCompositionLocalOf { false }
@Composable
fun AppTheme(content: @Composable () -> Unit) {
val context = LocalContext.current
val reduceMotion = remember {
Settings.Global.getFloat(context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f) == 0f
}
CompositionLocalProvider(LocalReducedMotion provides reduceMotion) { MaterialTheme { content() } }
}
// at the call site
AnimatedVisibility(
visible = isVisible,
enter = if (LocalReducedMotion.current) EnterTransition.None else fadeIn() + slideInVertically(),
) { Content() }
(staticCompositionLocalOf + 无键 remember 会在每个 Activity 中读取一次设置;如需实时更新,请改用 compositionLocalOf + 观察 ANIMATOR_DURATION_SCALE 的 ContentObserver。)
M3 合规性审查
在审查屏幕或功能是否符合 Material Design 3 时使用此清单——这是很容易凭记忆遗漏的部分。为每个类别评定通过 / 部分通过 / 不通过,然后在发布前修复所有部分通过或不通过的项目。
1. 颜色令牌
- 所有颜色均引用
MaterialTheme.colorScheme中的角色——不使用硬编码的十六进制值/ARGB。 - 正确使用角色:
primary用于关键操作,secondary/tertiary用于次要内容 / 强调色,error用于错误;正确搭配on*;分层表面使用surfaceContainerLow/High,而不是任意灰色。 - 轮廓:需要 3:1 对比度的交互边界(字段边框、焦点环)使用
outline,装饰性分隔线使用outlineVariant。 - Android 12+ 上使用动态颜色,并提供静态回退方案。
2. 字体排版
- 所有文本均来自
MaterialTheme.typography——不使用内联fontSize/fontWeight。 - 正确使用字体层级:主视觉使用
display*,章节标题使用headline*,卡片/对话框标题使用title*,正文内容使用body*,按钮/说明文字使用label*。
3. 形状
- 圆角半径取自
MaterialTheme.shapes,不使用硬编码的RoundedCornerShape。 - 层级:芯片使用
extraSmall(4dp),卡片使用small(8dp),对话框使用medium(12dp),底部面板使用large(16dp),FAB 使用extraLarge(28dp)。保持形状风格一致。
4. 高度与表面
- 通过色调颜色(表面容器)体现高度,而非投影;投影高度仅用于对话框、菜单和 FAB。
- 优先使用
ElevatedCard/ElevatedButton,而不是手动设置shadowElevation。 - 容器层级的色调应单调递增(
surfaceContainerLowest < … < Highest)——如果相邻两层在任一主题下呈现相同颜色,高度提示就会失效。
5. 组件
- 使用 M3 组件(
androidx.compose.material3.*),不使用 M2(androidx.compose.material.*),且同一屏幕上不得混用 M2/M3。 - 按设计用途使用组件:用
FloatingActionButton执行主要操作,用Card对内容分组,用TopAppBar承载屏幕级操作。
快速 grep 检查
在项目根目录运行——每个匹配项都属于类别 1/3/5 的违规项,应在人为审核前进行分类处理:
rg --type kt 'Color\(0x[0-9a-fA-F]{6,8}\)' --files-with-matches | head # 1: hardcoded colors
rg --type kt 'RoundedCornerShape\(\s*\d+(?:\.\d+)?\s*\.dp\s*\)' --files-with-matches | head # 3: hardcoded radii
rg --type kt 'import androidx\.compose\.material\.' --files-with-matches | head # 5: Material 2 imports
6. 布局与间距
- 内边距和外边距采用 8dp 网格;适配 compact/medium/expanded 断点;屏幕映射到标准布局(Feed、List-Detail、Supporting Pane)。
- 宽屏上限制内容宽度——在 Large 屏幕上将正文内容限制在约 840–1040dp 并居中;全宽布局用于导航框架,而非段落。
- 适配可折叠设备的姿态(内容不得跨越铰链;适用时采用桌面式/书本式布局)。
- Medium+ 上的对话框居中显示(而非全屏);bottom sheet 在 Expanded+ 上转换为 side sheet。
7. 导航
- 导航组件应与屏幕宽度匹配(Bottom Bar / Rail / Drawer);导航项同时包含图标和标签;当前目标位置通过
selected和活动指示器标明。
8. 动效
- 转场使用 M3 缓动和时长令牌;共享元素使用 300–500ms 的
Emphasized;进入/退出效果遵循 M3(淡入穿越、容器变换);动效可中断,并且遵循减少动态效果的设置。
9. 无障碍
- 有意义的图片/图标应设置
contentDescription;对比度符合 WCAG AA 标准(正文 4.5:1,大号文本和 UI 组件 3:1);触控目标 ≥48dp。 - 使用
semantics(mergeDescendants = true)合并复合项,使 TalkBack 将其作为一个整体播报(合并时将图标的contentDescription设为null)。 - 使用
semantics { heading() }标记分区标题,方便屏幕阅读器用户在不同分区间跳转。 - 遍历顺序应合乎逻辑(必要时使用
semantics { traversalIndex })。如果支持,应考虑用户可控的对比度(Standard/Medium/High)。
10. 主题一致性
- 使用单一
MaterialTheme(不嵌套或冲突使用主题);测试浅色和深色主题;通过CompositionLocal扩展自定义主题,而非使用全局变量;通过自定义ColorScheme设置品牌颜色,而非逐个组件覆盖。
审核摘要模板
Screen: [name] Date: [date]
| # | Category | Score | Notes |
|---|---------------------|---------|------------------------|
| 1 | Color tokens | Pass | |
| 2 | Typography | Partial | bodySmall hardcoded |
| 5 | Components | Fail | M2 Scaffold still used |
| 6 | Layout & spacing | Partial | No tablet breakpoint |
| 9 | Accessibility | Partial | Missing headings |
…
Action items:
- [ ] ...