mcpField
A
android-ux

android-ux

github.com/rcosteira79设计与 UI165166 次安装6 周前更新
代码仓库

关于 android-ux

面向 Android 开发者的参考技能,用于审查现有界面是否符合 Material Design 3,并处理较少见的平台行为。内容涵盖折叠屏、对比度、动效、无障碍和设计令牌。

主要功能

  1. 01Material 3 合规性审查
  2. 02折叠屏姿态布局指南
  3. 03应用内对比度方案指南
  4. 04动效令牌与减少动效
  5. 05无障碍与主题检查
  6. 06违规项快速 grep 检查

适用场景

  1. 01发布前审查现有界面
  2. 02适配折叠屏姿态布局
  3. 03检查动效和对比度表现
  4. 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…short450–200ms微交互、状态变化(涟漪、选择、开关)
medium1…medium4250–400ms标准转场(屏幕进入/退出、展开、显示)
long1…long4450–600ms容器变换、大型表面之间的淡入淡出
extraLong1…extraLong4700–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:
- [ ] ...

评论

支持 Markdown