mcpField
J
jetpack-compose-m3

jetpack-compose-m3

github.com/android开发10.0k296 次安装2 天前更新
代码仓库

关于 jetpack-compose-m3

使用 Wear Compose Material3 构建和迁移 Wear OS 界面的技能,指导开发者检查版本与组件示例,并遵循适用于 Wear 的布局和导航规范。

主要功能

  1. 01Wear Compose Material3 迁移指南
  2. 02版本与兼容性检查
  3. 03组件示例核验
  4. 04Scaffold 与列表布局指南
  5. 05Material 主题与默认值
  6. 06Wear 导航规范

适用场景

  1. 01迁移旧版 Wear Compose 页面
  2. 02添加 Wear Material3 组件
  3. 03构建可滚动的 Wear OS 页面

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/android/skills --skill jetpack-compose-m3

安装后在 Claude Code 中输入/jetpack-compose-m3确认已加载。

附带文件references/android/training/wearables/compose/migrate-to-material3.md

详细介绍

前提条件与兼容性

  1. Wear OS Compose Material3 版本: 如果有可用的内部工具来确定 androidx.wear.compose:compose-material3 的最新稳定版本 {VERSION},请使用该工具。
  2. 严格遵循: 如果某个版本被列为稳定版,就必须使用该版本,除非用户另有要求。不要因为编辑器中出现初始的“Unresolved reference”错误或过时的网页搜索结果而降级。
  3. Kotlin 版本: 使用 Wear Compose Material3 时,Kotlin 版本必须为 2.0.0 或 更高版本。
  4. Compose 编译器:
    • 如果 Kotlin 版本为 2.0.0+,项目必须使用 org.jetbrains.kotlin.plugin.compose Gradle 插件。
    • 如果 Kotlin 版本为 < 2.0.0,项目必须在 composeOptions 中使用 kotlinCompilerExtensionVersion,并与 Compose 与 Kotlin 兼容性映射表匹配。
  5. 最低 SDK: 确保 minSdk 至少为 25(Wear OS 2.0)。
  6. 样例提取要求:Wear Compose 库附带额外的 JAR 文件,其中包含每个组件各自的样例。在 Capability 2 中的样例提取到本地缓存之前,不得提出代码更改。库源文件并不完整,不能替代这些样例;跳过提取属于环境设置失败。

注意事项

  1. 必须同步并验证: 在 libs.versions.toml 或 build.gradle.kts 中更新版本后,必须先执行 Gradle 同步,再重构任何代码。这样可以确保环境已正确解析这些库。
  2. 禁止猜测(错误处理流程): 如果成功同步后遇到“Unresolved Reference”或 API 不匹配,不要尝试通过降低库版本来“修复”。

能力与工具

Capability 1:迁移

从较旧版本的 Wear OS Compose 或 Horologist 迁移时,请遵循以下指导。

  1. 除非开发者另有说明,否则使用 {VERSION} 中最新的稳定版 Wear Compose Material3。
  2. 阅读迁移指南。
  3. 使用迁移指南中的官方组件映射。
  4. 重构任何组件(例如,将 Chip -> Button)之前,请检查参数名称、插槽类型和“Expressive”设计标记。
  5. 不要使用 Horologist Composables、Compose Layout 或 Compose Material 库。
  6. 始终对照 Capability 3 中的组件指导进行检查。
  7. 迁移后,截图测试可能会失败:即使迁移到非常相似的组件,预期的默认内边距和位置也会发生变化。不要试图刻意匹配迁移前的截图,应优先采用 Material3 默认值。
Capability 2:组件样例

Wear Compose 为每个组件都提供了独立样例,位于 <artifact>-<version>-samples-sources.jar 文件中。使用 compose-material3、compose-foundation 或 compose-navigation3 时,Gradle 会自动下载这些 JAR 文件以及主库 JAR。

添加或调整 Wear Compose Material3 组件时,请使用规范的组件样例。

严格遵循:提取样例并非可选步骤。在提取并阅读样例之前,禁止实现任何代码。使用其他搜索工具替代此步骤,或假定库文档已足够,均违反协议。继续之前,必须通过读取一个样例文件来验证本地缓存。

步骤 1:准备
  1. 检查 build.gradle.kts 或 libs.versions.toml,确保 Wear Compose 版本与 {VERSION} 匹配。
  2. 执行 Gradle 同步,确保已下载必要的依赖项。
步骤 2:检查本地缓存
  1. 定义缓存目录路径:<SKILL_ROOT>/samples/{VERSION}/。不要选择其他位置。
  2. 检查此目录是否存在,并且是否包含带有 .kt 文件的子目录。
    • 如果是(缓存命中): 继续执行步骤 4。
    • 如果否(缓存未命中): 继续执行步骤 3。
步骤 3:检查 Gradle 缓存
  1. 示例源文件存储在 Gradle 缓存中。为避免缓慢的暴力搜索:

    • 确定 Gradle 用户主目录(通常为 ~/.gradle,也可检查 $GRADLE_USER_HOME)。
    • 缓存根目录为 <GRADLE_USER_HOME>/caches。将其称为 <CACHE_ROOT>。
  2. 将列表 ["material3", "foundation"] 中的项目定义为 {ARTIFACT}。如果使用 androidx.wear.compose.navigation3 库,也将 "navigation3" 加入列表。

  3. 对列表中的每个 {ARTIFACT}:

    • 构造库的预期相对路径段:androidx.wear.compose/compose-{ARTIFACT}/{VERSION}。

    • 运行有针对性的 find 命令。以下示例经过了效率优化:

      find <CACHE_ROOT>/modules-2/files-2.1/androidx.wear.compose/compose-{ARTIFACT}/{VERSION}/ \
        -name "*samples-sources.jar"
      
  4. 将此 JAR 用作官方示例源文件。

  5. 使用 unzip -j 将每个 JAR 的内容解压到 <SKILL_ROOT>/samples/{VERSION}/{ARTIFACT}/,以扁平化目录结构。

  6. 直接继续执行步骤 4。

步骤 4:阅读示例并实现
  1. 阅读相关的 .kt 示例文件。
  2. 将这些与版本匹配的官方示例作为以下内容的准确信息来源:
    • 必需参数和插槽名称。
    • 默认样式和字体排版令牌。
    • 交互行为(例如:onClick、onLongClick)。
    • 组件嵌套关系(例如:AppScaffold -> ScreenScaffold)。
能力 3:组件使用指导

强制要求:将此能力用作检查清单,核对任何组件的使用情况。它提供了关于如何在实践中使用各个组件的更全面指导,而不仅仅是组件语法。

  1. AppScaffold 和 ScreenScaffold

    • [ ] 将 AppScaffold 用作外层容器,并以 ScreenScaffold 作为其子项。
    • [ ] 只使用一个 AppScaffold,并可使用任意数量的 ScreenScaffold。
  2. ScalingLazyColumn - 改用 TransformingLazyColumn。

  3. TransformingLazyColumn - 你需要导入以下内容:

    import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
    import androidx.wear.compose.foundation.lazy.TransformingLazyColumnDefaults
    import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
    // ...
    import androidx.wear.compose.material3.lazy.rememberTransformationSpec
    import androidx.wear.compose.material3.lazy.transformedHeight
    

    规范示例:

    val columnState = rememberTransformingLazyColumnState()
    val transformationSpec = rememberTransformationSpec()
    ScreenScaffold(
        scrollState = columnState
    ) { contentPadding ->
        TransformingLazyColumn(
            state = columnState,
            contentPadding = contentPadding
        ) {
            item {
                ListHeader(
                    modifier = Modifier
                        .fillMaxWidth()
                        .transformedHeight(this, transformationSpec)
                        .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding),
                    transformation = SurfaceTransformation(transformationSpec)
                ) {
                    Text(text = "Header")
                }
            }
            // ... other items
            item {
                Button(
                    modifier = Modifier
                        .fillMaxWidth()
                        .transformedHeight(this, transformationSpec)
                        .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding),
                    transformation = SurfaceTransformation(transformationSpec),
                    onClick = { /* ... */ },
                    icon = {
                        Icon(
                            imageVector = Icons.Default.Build,
                            contentDescription = "build",
                        )
                    },
                ) {
                    Text(
                        text = "Build",
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis,
                    )
                }
            }
        }
    }
    

    • [ ] 使用 TransformingLazyColumn,而不是 ScalingLazyColumn。
    • [ ] 必须将 ScreenScaffold 的 contentPadding 参数传递给 TransformingLazyColumn。
    • [ ] 使用 minimumVerticalContentPadding 修饰符设置所需的顶部和底部内边距。
      • 该值应取自默认值,例如 ButtonDefaults、CardDefaults、`ListHeaderDefaults。
      • 注意:这是一个作用域修饰符,可在 TransformingLazyColumnItemScope 中使用。
    • [ ] 确保列表会变形和缩放。
    • [ ] 使用 transformedHeight 修饰符。
    • [ ] 使用 transform = SurfaceTransform(...)。
    • [ ] 如果要配置可吸附的列表,请同时使用 flingBehavior 和 rotaryScrollableBehavior:
    val columnState = rememberTransformingLazyColumnState()
    ScreenScaffold(scrollState = columnState) { contentPadding ->
        TransformingLazyColumn(
            state = columnState,
            flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState),
            rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(columnState)
        ) {
            // ...
            // ...
        }
    }
    

  4. ScreenScaffold

    • [ ] 使用 !LocalScrollCaptureInProgress.current 对 scrollIndicator 进行保护。
  5. EdgeButton

    • [ ] 不要将其用作 TransformingLazyColumn 中的最后一项。请改用 ScreenScaffold 中的插槽。
    • [ ] 在 TransformingLazyColumn 中使用时,添加所需的过滚行为:
    val columnState = rememberTransformingLazyColumnState()
    ScreenScaffold(
        scrollState = columnState,
        edgeButton = {
            EdgeButton(
                onClick = { /* TODO */ },
                modifier = Modifier.scrollable(
                    columnState,
                    orientation = Orientation.Vertical,
                    reverseDirection = true,
                    // Apply overscroll to the EdgeButton for proper scrolling behavior.
                    overscrollEffect = rememberOverscrollEffect(),
                )
            ) {
                Text("More")
            }
        }
    ) { contentPadding ->
        TransformingLazyColumn(
            contentPadding = contentPadding,
            state = columnState,
        ) {
            // ...
            // ...
        }
    }
    

  6. Column

    • [ ] 如果屏幕永远不会滚动(即使使用最大的系统字体),则将其用作 ScreenScaffold 的直接子项。
    • [ ] 其他情况下均改用 TransformingLazyColumn。
  7. 样式

    • [ ] 不要将文本大小硬编码,请使用 MaterialTheme 中的 typography。
    • [ ] 不要将颜色硬编码,请使用 MaterialTheme 中的 colorScheme。
  8. 使用组件默认值:

    • [ ] Button 等组件都有对应的 ButtonDefaults 对象。
    • 使用内边距和样式值时,请检查并使用任何组件对应的 *Defaults 对象,优先于硬编码值。
  9. 使用 Wear 专用预览:

    • [ ] WearPreviewDevices
    • [ ] WearPreviewFontScales
  10. 环境模式

    • [ ] 使用 LocalAmbientModeManager,而不是 AmbientLifecycleObserver。
  11. 导航

    • [ ] 全新添加导航时,请使用 Navigation3。
    • [ ] 在 Wear OS 中使用 Navigation3 时,请使用 Wear Compose compose-navigation3 库中的 SwipeDismissableSceneStrategy()。

评论

支持 Markdown