jetpack-compose-m3

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Prerequisites & Compatibility

前提条件与兼容性

  1. Wear OS Compose Material3 version: If an internal tool is available to establish the latest stable version
    {VERSION}
    of
    androidx.wear.compose:compose-material3
    , use that tool.
    • Otherwise, fetch the official Maven metadata XML to identify
      {VERSION}
      (highest number, ignoring
      -alpha
      ,
      -beta
      , or
      -rc
      )
      1. Strict Compliance: If a version is listed as stable, you MUST use it, unless overridden by the user. Do not downgrade based on initial "Unresolved reference" errors in the editor or outdated web search results.
  2. Kotlin Version: For Wear Compose Material3, use Kotlin 2.0.0 or higher.
  3. Compose Compiler:
    • If Kotlin version is 2.0.0+ , the project must use the
      org.jetbrains.kotlin.plugin.compose
      Gradle plugin.
    • If Kotlin version is < 2.0.0 , the project must use
      kotlinCompilerExtensionVersion
      in
      composeOptions
      , matching the Compose to Kotlin Compatibility Map.
      1. Min SDK: Ensure
        minSdk
        is at least 25 (Wear OS 2.0).
  4. Sample Extraction Mandate: Wear Compose libraries ship with an additional JAR file which contains individual samples for each and every component. You MUST NOT propose code changes until the samples in Capability
    files are incomplete and NOT a substitute for these samples; bypassing extraction is an environment setup failure.
  1. Wear OS Compose Material3 版本: 如果有内部工具可获取
    androidx.wear.compose:compose-material3
    最新稳定版本
    {VERSION}
    ,请使用该工具。
    • 若没有,则获取官方Maven元数据XML来确定
      {VERSION}
      (选择最高版本号,忽略
      -alpha
      -beta
      -rc
      后缀的版本)
      1. 严格合规: 若列出了稳定版本,必须使用该版本,除非用户另行指定。请勿因编辑器初始出现的"未解析引用"错误或过时的网页搜索结果而降级版本。
  2. Kotlin版本: 使用Wear Compose Material3时,需使用Kotlin 2.0.0或更高版本
  3. Compose编译器:
    • 若Kotlin版本为2.0.0+,项目必须使用
      org.jetbrains.kotlin.plugin.compose
      Gradle插件。
    • 若Kotlin版本**<2.0.0**,项目必须在
      composeOptions
      中配置
      kotlinCompilerExtensionVersion
      ,版本需与Compose与Kotlin兼容性对照表匹配。
      1. 最低SDK版本: 确保
        minSdk
        至少为25(对应Wear OS 2.0)。
  4. 示例提取要求:Wear Compose库附带一个额外的JAR文件,其中包含每个组件的独立示例。在提取并查看这些示例之前,不得提出任何代码修改建议;Capability文件中的示例并不完整,无法替代这些官方示例,跳过提取步骤属于环境配置失败。

Gotchas

注意事项

  1. Mandatory Sync & Validation: After updating versions in
    libs.versions.toml
    or
    build.gradle.kts
    , you must perform a Gradle sync before refactoring any code. This ensures the environment has resolved the libraries correctly.
  2. Prohibition of Guessing (Error Protocol): If you encounter an 'Unresolved Reference' or API mismatch after a successful sync, do not attempt to 'fix' it by downgrading the library version.
  1. 必须同步与验证:
    libs.versions.toml
    build.gradle.kts
    中更新版本后,必须先执行Gradle同步,再进行任何代码重构。这可确保环境已正确解析库依赖。
  2. 禁止猜测(错误处理规则): 若同步成功后仍遇到"未解析引用"或API不匹配问题,请勿通过降级库版本来尝试"修复"。

Capabilities and Tools

功能与工具

Capability 1: Migration

功能1:迁移

Use this guidance when migrating from an older version of Wear OS Compose or Horologist.
  1. Unless otherwise indicated by the developer, use the latest stable version of Wear Compose Material3 from
    {VERSION}
    .
  2. Read the migration guide
  3. Use the official component mappings from the migration guide.
  4. Before refactoring any component (e.g.,
    Chip
    ->
    Button
    ), check the parameter names, slot types, and "Expressive" design tokens.
  5. Do not use the Horologist Composables, Compose Layout, or Compose Material libraries.
  6. Always check against the component guidance in Capability #3.
  7. Expect screenshot tests to fail when a migration has been performed: Even when migrating to very similar components, expected defaults for padding and positioning will have changed. Do not seek to artificially match the pre-migration screenshot, but give preference to the Material3 defaults.
当从旧版本Wear OS Compose或Horologist迁移时,请遵循以下指导。
  1. 除非开发者另有说明,否则使用
    {VERSION}
    指定的Wear Compose Material3最新稳定版本。
  2. 阅读迁移指南
  3. 使用迁移指南中的官方组件映射关系。
  4. 在重构任何组件(如
    Chip
    ->
    Button
    )之前,检查参数名称、插槽类型和"Expressive"设计标记。
  5. 请勿使用Horologist Composables、Compose Layout或Compose Material库。
  6. 务必对照功能3中的组件使用指南进行检查。
  7. 迁移完成后,截图测试可能会失败:即使迁移到非常相似的组件,内边距和位置的默认值也可能已更改。请勿刻意匹配迁移前的截图,应优先使用Material3的默认设置。

Capability 2: Component samples

功能2:组件示例

Wear Compose includes individual component samples for each and every component, within the
<artifact>-<version>-samples-sources.jar
file. Gradle automatically downloads these JAR files along with the main library JAR when using any of
compose-material3
,
compose-foundation
or
compose-navigation3
.
Use the canonical component samples whenever adding or adjusting a Wear Compose Material3 component.
STRICT COMPLIANCE: Extraction is NOT optional. You are FORBIDDEN from implementing any code until samples are extracted and read. Bypassing this step with alternative search tools or by assuming library documentation is sufficient is a protocol breach. You MUST verify the local cache by reading a sample file before proceeding.
Wear Compose在
<artifact>-<version>-samples-sources.jar
文件中包含每个组件的独立示例。当使用
compose-material3
compose-foundation
compose-navigation3
中的任意一个库时,Gradle会自动将这些JAR文件与主库JAR一起下载。
添加或调整Wear Compose Material3组件时,请使用官方标准组件示例。
严格合规:提取示例并非可选步骤。在提取并阅读示例之前,禁止编写任何代码。使用其他搜索工具或假设库文档足够而跳过此步骤属于违反规则。继续操作前,必须通过阅读示例文件来验证本地缓存。

Step 1: Prepare

步骤1:准备

  1. Check the
    build.gradle.kts
    or
    libs.versions.toml
    to ensure the Wear Compose version matches
    {VERSION}
    .
  2. Ensure that the necessary dependencies are downloaded by doing a Gradle sync.
  1. 检查
    build.gradle.kts
    libs.versions.toml
    ,确保Wear Compose版本与
    {VERSION}
    一致。
  2. 执行Gradle同步,确保已下载必要的依赖项。

Step 2: Check the Local Cache

步骤2:检查本地缓存

  1. Define the cache directory path:
    <SKILL_ROOT>/samples/{VERSION}/
    . Do NOT choose your own different location.
  2. Check if this directory exists and contains subdirectories with
    .kt
    files.
    • IF YES (Cache Hit): Proceed to Step 4.
    • IF NO (Cache Miss): Proceed to Step 3.
  1. 定义缓存目录路径:
    <SKILL_ROOT>/samples/{VERSION}/
    。请勿自行选择其他路径。
  2. 检查该目录是否存在且包含带有
    .kt
    文件的子目录。
    • 如果存在(缓存命中): 继续执行步骤4
    • 如果不存在(缓存未命中): 继续执行步骤3

Step 3: Check the Gradle Cache

步骤3:检查Gradle缓存

  1. Sample sources are stored in the Gradle cache. To avoid slow, brute-force searches:
    • Determine the Gradle User Home (usually
      ~/.gradle
      , or check
      $GRADLE_USER_HOME
      ).
    • The cache root is
      <GRADLE_USER_HOME>/caches
      . Call this
      <CACHE_ROOT>
      .
  2. Define
    {ARTIFACT}
    as the items in the list
    ["material3", "foundation"]
    . Also include "navigation3" in the list if the
    androidx.wear.compose.navigation3
    library is being used.
  3. For each
    {ARTIFACT}
    in the list:
    • Construct the expected relative path segment for the library:
      androidx.wear.compose/compose-{ARTIFACT}/{VERSION}
      .
    • Run a targeted
      find
      command. Here is an example which is constructed for efficiency:
      find <CACHE_ROOT>/modules-2/files-2.1/androidx.wear.compose/compose-{ARTIFACT}/{VERSION}/ \
        -name "*samples-sources.jar"
  4. Use this JAR as the official sample sources.
  5. Extract the contents of each JAR to
    <SKILL_ROOT>/samples/{VERSION}/{ARTIFACT}/
    using
    unzip -j
    to flatten the structure.
  6. Proceed directly to step 4.
  1. 示例源码存储在Gradle缓存中。为避免缓慢的暴力搜索:
    • 确定Gradle用户主目录(通常为
      ~/.gradle
      ,或检查
      $GRADLE_USER_HOME
      环境变量)。
    • 缓存根目录为
      <GRADLE_USER_HOME>/caches
      ,记为
      <CACHE_ROOT>
  2. {ARTIFACT}
    定义为列表
    ["material3", "foundation"]
    中的项。如果使用了
    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

Step 4: Read Samples and Implement

步骤4:阅读示例并实现

  1. Read the relevant
    .kt
    sample files.
  2. Use these official, version-matched samples as the for:
    • Required parameters and slot names.
    • Default styling and typography tokens.
    • Interactive behaviors (e.g.,
      onClick
      ,
      onLongClick
      ).
    • Component nesting (e.g.,
      AppScaffold
      ->
      ScreenScaffold
      ).
  1. 阅读相关的
    .kt
    示例文件。
  2. 将这些官方、版本匹配的示例作为参考,用于:
    • 必填参数和插槽名称。
    • 默认样式和排版标记。
    • 交互行为(如
      onClick
      onLongClick
      )。
    • 组件嵌套(如
      AppScaffold
      ->
      ScreenScaffold
      )。

Capability 3: Component guidance

功能3:组件使用指南

Mandatory: Use this capability as a checklist against any component use. It provides more holistic guidance on how to use each component in practice, beyond the component syntax.
  1. AppScaffold
    and
    ScreenScaffold
    • [ ] Use
      AppScaffold
      as the outer container, with
      ScreenScaffold
      children.
    • [ ] Use only ONE
      AppScaffold
      and any number of
      ScreenScaffold
      .
  2. ScalingLazyColumn
    - Use
    TransformingLazyColumn
    instead.
  3. TransformingLazyColumn
    You will need the following imports:
    kotlin
    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
    <br />
    Canonical example:
    kotlin
    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,
                    )
                }
            }
        }
    }
    <br />
    • [ ] Use
      TransformingLazyColumn
      instead of
      ScalingLazyColumn
    • [ ] You must pass the
      contentPadding
      parameter from
      ScreenScaffold
      to the
      TransformingLazyColumn
      .
    • [ ] Use the
      minimumVerticalContentPadding
      modifier to achieve required padding top and bottom.
      • This expects a value from defaults, such as
        ButtonDefaults
        ,
        CardDefaults
        , `ListHeaderDefaults.
      • Note: This is a scoped modifier available within
        TransformingLazyColumnItemScope
        .
    • [ ] Ensure the list morphs and scales.
    • [ ] Use
      transformedHeight
      modifier.
    • [ ] Use
      transform = SurfaceTransform(...)
      .
    • [ ] If configuring a list for snapping, use
      flingBehavior
      and
      rotaryScrollableBehavior
      together:
    kotlin
    val columnState = rememberTransformingLazyColumnState()
    ScreenScaffold(scrollState = columnState) { contentPadding ->
        TransformingLazyColumn(
            state = columnState,
            flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState),
            rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(columnState)
        ) {
            // ...
            // ...
        }
    }
    <br />
  4. ScreenScaffold
    • [ ] Guard the
      scrollIndicator
      with
      !LocalScrollCaptureInProgress.current
  5. EdgeButton
    • [ ] Do NOT use as the final item within a
      TransformingLazyColumn
      . Instead, use the slot in
      ScreenScaffold
      .
    • [ ] When used in a
      TransformingLazyColumn
      , add the required overscroll behavior:
    kotlin
    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,
        ) {
            // ...
            // ...
        }
    }
    <br />
  6. Column
    • [ ] USE as a direct child of
      ScreenScaffold
      if the screen is will never scroll, even with the largest system font.
    • [ ] Use
      TransformingLazyColumn
      instead for all other cases.
  7. Styles
    • [ ] Do NOT hard-code text sizes, use
      typography
      from
      MaterialTheme
      .
    • [ ] Do NOT hard-code colors, use
      colorScheme
      from
      MaterialTheme
      .
  8. Use component defaults
    • [ ] Components such as
      Button
      have a corresponding
      ButtonDefaults
      object.
    • Check for and use the
      *Defaults
      object for any component when working with padding and styling values, in preference to hard-coded values.
  9. Use Wear specific previews
    • [ ]
      WearPreviewDevices
    • [ ]
      WearPreviewFontScales
  10. Ambient mode
    • [ ] Use
      LocalAmbientModeManager
      instead of
      AmbientLifecycleObserver
      .
  11. Navigation
    • [ ] When adding navigation fresh, use Navigation3.
    • [ ] For Navigation3 in Wear OS, use
      SwipeDismissableSceneStrategy()
      from the Wear Compose
      compose-navigation3
      library.
强制要求:将此功能作为组件使用的检查清单。它提供了超越组件语法的、更全面的实际使用指导。
  1. AppScaffold
    ScreenScaffold
    • 使用
      AppScaffold
      作为外层容器,
      ScreenScaffold
      作为其子组件。
    • 只能使用一个
      AppScaffold
      ,可使用任意数量的
      ScreenScaffold
  2. ScalingLazyColumn
    - 请改用
    TransformingLazyColumn
  3. TransformingLazyColumn
    你需要导入以下内容:
    kotlin
    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
    <br />
    标准示例
    kotlin
    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,
                    )
                }
            }
        }
    }
    <br />
    • 使用
      TransformingLazyColumn
      替代
      ScalingLazyColumn
    • 必须将
      ScreenScaffold
      contentPadding
      参数传递给
      TransformingLazyColumn
    • 使用
      minimumVerticalContentPadding
      修饰符来设置所需的上下内边距。
      • 该值应取自默认配置对象,如
        ButtonDefaults
        CardDefaults
        ListHeaderDefaults
      • 注意:这是
        TransformingLazyColumnItemScope
        内可用的作用域修饰符。
    • 确保列表可变形和缩放。
    • 使用
      transformedHeight
      修饰符。
    • 使用
      transform = SurfaceTransform(...)
    • 如果配置列表为可吸附(snapping)模式,需同时使用
      flingBehavior
      rotaryScrollableBehavior
    kotlin
    val columnState = rememberTransformingLazyColumnState()
    ScreenScaffold(scrollState = columnState) { contentPadding ->
        TransformingLazyColumn(
            state = columnState,
            flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState),
            rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(columnState)
        ) {
            // ...
            // ...
        }
    }
    <br />
  4. ScreenScaffold
    • 使用
      !LocalScrollCaptureInProgress.current
      来保护
      scrollIndicator
  5. EdgeButton
    • 请勿将其用作
      TransformingLazyColumn
      的最后一项。应改用
      ScreenScaffold
      中的插槽。
    • 若在
      TransformingLazyColumn
      中使用,需添加所需的过度滚动行为:
    kotlin
    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,
        ) {
            // ...
            // ...
        }
    }
    <br />
  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()