移动/游戏
在 Android Jetpack Compose…
当需要把 Compose 自定义 UI 组件从硬编码样式参数迁移到统一 Style、并用 Modifier.styleable 处理状态样式时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Android Jetpack Co特定
解决思路
- 开始前提醒用户:此技能为 EXPERIMENTAL,需要升级到 Compose alpha 版本并 opt-in Experimental APIs。
- 仅对自定义 UI 组件和自定义主题执行迁移;不要用于 Material Design 组件 Styles。
- 升级依赖:确保项目使用 `compileSdk` 37 或更高。
- 升级依赖:确保使用 `androidx.compose.foundation:foundation` 版本 `1.12.0-alpha01` 或更高。
- 或确保使用 Compose BOM 版本 `2026.04.01` 或更高。
- 确保 API 使用精确包名:`import androidx.compose.foundation.style.Style`。
- 在模块的 `build.gradle.kts` 中添加项目级编译器选项以 opt-in 实验 API:`kotlin { compilerOptions { jvmTarget = JvmTarget.fromTarget("17") freeCompilerArgs.add("-opt-in=androidx.compose.foundation.style.ExperimentalFoundationStyleApi") } }`。
- 基础 Style 用法:按 Compose Styles Fundamentals Guide 在组件上设置背景、尺寸和对齐方式。
- 状态与过渡:按 Animations and State-Based Styling Guide 为 pressed、hovered 等状态切换配置属性变化。
- 架构取舍:按 Styles versus Modifiers Comparison 决定何时使用 Style 而不是标准 Modifier。
- 主题级集成:按 Theming with Styles 和 Custom Themes in Compose 将样式定义与自定义主题连接起来。
- Step 1.1:定位中心主题文件,例如 `Theme.kt`。
- Step 1.2:识别设计 token,记录颜色、排版和形状的引用,例如 `LocalColorScheme`、`LocalTypography` 或 `LocalShapes`。
- Step 1.3:如果项目缺少 Jetpack Compose 依赖,停止,并指导用户先迁移到 Jetpack Compose。
- Step 1.4:如果项目导入 `androidx.compose.material.MaterialTheme`,建议先迁移到 Material 3 再继续。
- Step 2.1:在主题目录中创建新文件 `ComponentStyles.kt`。
- Step 2.2:定义顶层 data class 或 object 保存组件样式,例如 `object ExampleComponentStyles { val customButtonStyle: Style = { } val customTextFieldStyle: Style = { } }`。
- Step 2.3:通过自定义主题以静态引用暴露该类,不要使用 `CompositionLocals`,例如在 `companion object` 中添加 `val styles: ComponentStyles = ComponentStyles`。
- Step 2.4:如果主题 token 通过 `CompositionLocals` 暴露,为 `StyleScope` 提供扩展以直接引用主题 token,例如 `val StyleScope.colors: JetsnackColors get() = LocalJetsnackTheme.currentValue.colors`、`val StyleScope.typography: androidx.compose.material3.Typography get() = LocalJetsnackTheme.currentValue.typography`、`val StyleScope.shapes: Shapes get() = LocalJetsnackTheme.currentValue.shapes`。
- Step 3:对每个自定义组件(例如 `CustomButton`)执行以下迁移序列。
- Step 3.1:建立视觉基线(如果可用模拟器):如果无法运行 Android 模拟器,完全跳过本步并进入下一步;如果可以运行,则捕获基线截图。Option A:定位并运行组件已有的截图测试。Option B:如果没有测试,使用项目现有测试框架创建测试并运行。Option C:如果没有框架,使用 UI Automator 或 Espresso 创建最小截图测试并运行。
- Step 3.2:移除单独样式参数:从函数签名中移除 `backgroundColor`、`shape`、`textStyle`、`contentPadding` 等任何 `StyleScope` 支持的样式参数。
- Step 3.3:添加 style 参数:在函数签名中添加 `style: Style = Style`;默认值必须精确为 `Style`,不要用 `ChipStyleDefault` 等具体样式默认值。
- Step 3.4:声明状态跟踪:如果组件可交互,使用 interaction source 创建 `MutableStyleState`;在 Composable 内更新状态字段(例如 `isEnabled`)以正确跟踪状态。
- Step 3.5:应用 styleable modifier:把根元素上的具体布局 modifier 替换为 `Modifier.styleable()`。
- Step 3.6:把默认值移到 ComponentStyles:把组件定义中的硬编码值移到 `ComponentStyles.kt` 中专门的 `Style` 实例。
- Step 3.7:验证组件:把开始时拍的基线截图与新的 composable 渲染出的 Compose Preview 对比;忽略字符串内容,聚焦布局和样式;迭代 Compose 代码直到视觉一致;验证后为新的 composable 编写 Compose UI 测试。
- 迁移示例落地:迁移前 `CustomButton` 使用 `backgroundColor`、`disabledBackgroundColor`、`shape`、`textStyle` 等参数;迁移后在 `ComponentStyles.buttonStyle = Style { background(colors.brandLight); shape(shapes.extraLarge); minWidth(58.dp); minHeight(40.dp); textStyle(typography.labelLarge); disabled { background(colors.brandSecondary) } }`,组件签名添加 `style: Style = Style`,并用 `rememberUpdatedStyleState(interactionSource) { it.isEnabled = enabled }` 和 `.styleable(styleState, JetsnackTheme.styles.buttonStyle, style)`。
- Step 4.1:构建项目,确认没有编译错误。
- Step 4.2:运行模块的截图测试。
- Step 4.3:对比更新前后整个应用的视觉输出,确认没有视觉布局回归。
适用边界 · 注意事项
- 项目未使用 Jetpack Compose,或仍使用 `androidx.compose.material.MaterialTheme`(Material 2)时,先迁移到 Compose/Material 3 后再使用。
- 需要 Material Design 组件自带的 Styles 时,本技能不支持。
- 项目不能接受实验性 API、不能升级到 alpha 版 Compose 或不愿 opt-in `ExperimentalFoundationStyleApi` 时,不要使用。