styles
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLimitations
局限性
- Warn the user that this skill is EXPERIMENTAL and requires updating to alpha version of Compose and opting in to the Experimental APIs.
- This skill only supports custom UI components and custom themes.
- This skill does not support Material Design component Styles.
- 提醒用户本技能处于实验阶段,需要升级到Compose的alpha版本并启用Experimental APIs。
- 本技能仅支持自定义UI组件和自定义主题。
- 本技能不支持Material Design组件样式。
Prerequisites
前置条件
1. Upgrade dependencies
1. 升级依赖
- The project must use version 37 or higher.
compileSdk - The project must use version
androidx.compose.foundation:foundationor higher.1.12.0-alpha01 - Alternatively, the project must use Compose BOM version or higher.
2026.04.01 - The API requires this exact package:
import androidx.compose.foundation.style.Style
- 项目必须使用版本37或更高。
compileSdk - 项目必须使用版本
androidx.compose.foundation:foundation或更高。1.12.0-alpha01 - 或者,项目必须使用Compose BOM版本或更高。
2026.04.01 - 该API需要导入特定包:
import androidx.compose.foundation.style.Style
2. Configure compiler options to enable experimental API
2. 配置编译器选项以启用实验性API
You must opt-in to the experimental API at the project level. Add the following
block to your module's :
build.gradle.ktskotlin {
compilerOptions {
jvmTarget = JvmTarget.fromTarget("17")
freeCompilerArgs.add("-opt-in=androidx.compose.foundation.style.ExperimentalFoundationStyleApi")
}
}你必须在项目层面启用实验性API。在模块的中添加以下代码块:
build.gradle.ktskotlin {
compilerOptions {
jvmTarget = JvmTarget.fromTarget("17")
freeCompilerArgs.add("-opt-in=androidx.compose.foundation.style.ExperimentalFoundationStyleApi")
}
}Core workflows and guides
核心工作流与指南
Refer to the official documentation to complete specific development tasks:
- Basic Style Usage: To set backgrounds, sizes, and alignments on a component, follow the Compose Styles Fundamentals Guide.
- State and Transitions: To configure property changes for state shifts (like pressed or hovered), follow the Animations and State-Based Styling Guide.
- Architecture Trade offs: To decide when to use a Style versus a standard Modifier, follow the Styles versus Modifiers Comparison.
- Theme Level Integration: To connect style definitions with custom themes, follow Theming with Styles and Custom Themes in Compose.
请参考官方文档完成具体开发任务:
- 基础Style用法:如需为组件设置背景、尺寸和对齐方式,请遵循《Compose Styles基础指南》(references/android/develop/ui/compose/styles/fundamentals.md)。
- 状态与过渡:如需配置状态切换(如按压或悬停)时的属性变化,请遵循《动画与基于状态的样式指南》(references/android/develop/ui/compose/styles/state-animations.md)。
- 架构权衡:如需决定何时使用Style而非标准Modifier,请遵循《Style与Modifier对比》(references/android/develop/ui/compose/styles/styles-vs-modifiers.md)。
- 主题层面集成:如需将样式定义与自定义主题关联,请遵循《使用Styles进行主题化》(references/android/develop/ui/compose/styles/theming.md)和《Compose中的自定义主题》(references/android/develop/ui/compose/designsystems/custom.md)。
Step-by-Step Migration Workflow
分步迁移工作流
Step 1: Analyze theme structure
步骤1:分析主题结构
- Locate your central theme file (such as ).
Theme.kt - Identify design tokens. Note references for colors, typography, and shapes (for example, ,
LocalColorScheme, orLocalTypography).LocalShapes - If the project lacks Jetpack Compose dependencies, stop. Instruct the user to migrate to Jetpack Compose first.
- If the project imports , recommend migrating to Material 3 before proceeding.
androidx.compose.material.MaterialTheme
- 找到你的核心主题文件(如)。
Theme.kt - 识别设计标记。记录颜色、排版和形状的引用(例如、
LocalColorScheme或LocalTypography)。LocalShapes - 如果项目缺少Jetpack Compose依赖,请停止操作。指导用户先迁移到Jetpack Compose。
- 如果项目导入了,建议先迁移到Material 3再继续。
androidx.compose.material.MaterialTheme
Step 2: Establish ComponentStyles
ComponentStyles步骤2:创建ComponentStyles
ComponentStyles-
Create a new file namedin your theme directory.
ComponentStyles.kt -
Define a top-level data class to hold your component styles, for example, the Jetsnack one is called:
JetsnackStyles<br />kotlinobject ExampleComponentStyles { val customButtonStyle: Style = { } val customTextFieldStyle: Style = { } } -
Expose this class through your custom theme with a static reference, don't usehere as it's not required.
CompositionLocals<br />kotlin@Immutable class JetsnackTheme( // other Design system properties ) { companion object { val colors: CustomThemingWithStyles.JetsnackColors @Composable @ReadOnlyComposable get() = LocalJetsnackTheme.current.colors // ... // add helper static reference val styles: ComponentStyles = ComponentStyles } } -
Provide extensions onto reference theme tokens directly if they are exposed using
StyleScope. For example:CompositionLocals<br />kotlinval 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
-
在主题目录中创建一个名为的新文件。
ComponentStyles.kt -
定义一个顶层数据类来存储你的组件样式,例如Jetsnack项目中的:
JetsnackStyles<br />kotlinobject ExampleComponentStyles { val customButtonStyle: Style = { } val customTextFieldStyle: Style = { } } -
通过自定义主题的静态引用暴露此类,此处无需使用。
CompositionLocals<br />kotlin@Immutable class JetsnackTheme( // 其他设计系统属性 ) { companion object { val colors: CustomThemingWithStyles.JetsnackColors @Composable @ReadOnlyComposable get() = LocalJetsnackTheme.current.colors // ... // 添加辅助静态引用 val styles: ComponentStyles = ComponentStyles } } -
如果主题标记通过暴露,请在
CompositionLocals上提供扩展函数以直接引用这些标记。例如:StyleScope<br />kotlinval 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: Migrate a component to Styles API
步骤3:将组件迁移到Styles API
For each custom component (for example, ), complete the following
sequence:
CustomButton- If you are able to run an Android emulator, locate an existing screenshot test for the component. If none exists, create one using the existing project testing framework. If no framework exists, use UI Automator or Espresso to create a screenshot test with minimum required setup. Run the test and take a baseline screenshot of the Component. ELSE proceed to the next step without a screenshot test.
- Remove individual styling parameters : Remove styling parameters such as ,
backgroundColor,shape, andtextStylefrom the signature - anything thatcontentPaddingsupports.StyleScope - Add the style parameter : Add to the function signature.
style: Style = Style - Declare state tracking : If the component is interactable, create a using the interaction source. Update state fields (such as
MutableStyleState) inside the Composable to track the state correctly.isEnabled - Apply styleable modifier : Replace specific layout modifiers on the root element with .
Modifier.styleable() - Move defaults to ComponentStyles : Move hardcoded values from the component definition to a dedicated instance in
Style.ComponentStyles.kt - Validate component: Compare the baseline screenshot image taken at the start with the rendered Compose Preview of the new composable. Ignore string content; focus on layout and styling. Iterate on the Compose code until visual parity is achieved. Once verified, write a Compose UI test for the new composable.
对于每个自定义组件(如),完成以下步骤:
CustomButton- 如果可以运行Android模拟器,找到该组件现有的截图测试。如果没有,请使用项目现有的测试框架创建一个。如果没有测试框架,请使用UI Automator或Espresso创建一个最简配置的截图测试。运行测试并获取组件的基准截图。否则,直接进入下一步,无需截图测试。
- 移除单独的样式参数:从函数签名中移除、
backgroundColor、shape和textStyle等样式参数——所有contentPadding支持的参数都要移除。StyleScope - 添加style参数:在函数签名中添加。
style: Style = Style - 声明状态跟踪:如果组件是可交互的,使用交互源创建。在Composable内部更新状态字段(如
MutableStyleState)以正确跟踪状态。isEnabled - 应用styleable修饰符:将根元素上的特定布局修饰符替换为。
Modifier.styleable() - 将默认值迁移到ComponentStyles:将组件定义中的硬编码值移至中专门的
ComponentStyles.kt实例。Style - 验证组件:将开始时获取的基准截图与新Composable的预览渲染结果进行对比。忽略文本内容,重点关注布局和样式。迭代修改Compose代码直至视觉效果一致。验证通过后,为新Composable编写Compose UI测试。
Migration example
迁移示例
Before Migration:
kotlin
@Composable
fun CustomButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
backgroundColor: Color = JetsnackTheme.colors.brandLight,
disabledBackgroundColor: Color = JetsnackTheme.colors.brandSecondary,
shape: Shape = JetsnackTheme.shapes.extraLarge,
textStyle: TextStyle = JetsnackTheme.typography.labelLarge,
enabled: Boolean = true,
content: @Composable RowScope.() -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
Row(
modifier
.clickable(onClick = onClick, indication = null, interactionSource = interactionSource)
.background(if (enabled) backgroundColor else disabledBackgroundColor, shape)
.defaultMinSize(58.dp, 40.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content,
)
}After Migration:
kotlin
// Exposed via ComponentStyles.kt
object ComponentStyles {
val buttonStyle = Style {
background(colors.brandLight)
shape(shapes.extraLarge)
minWidth(58.dp)
minHeight(40.dp)
textStyle(typography.labelLarge)
disabled {
background(colors.brandSecondary)
}
}
}
@Composable
fun CustomButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
style: Style = Style,
enabled: Boolean = true,
content: @Composable RowScope.() -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
val styleState = rememberUpdatedStyleState(interactionSource) {
it.isEnabled = enabled
}
Row(
modifier
.clickable(onClick = onClick, indication = null, interactionSource = interactionSource)
.styleable(styleState, JetsnackTheme.styles.buttonStyle, style),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content,
)
}迁移前:
kotlin
@Composable
fun CustomButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
backgroundColor: Color = JetsnackTheme.colors.brandLight,
disabledBackgroundColor: Color = JetsnackTheme.colors.brandSecondary,
shape: Shape = JetsnackTheme.shapes.extraLarge,
textStyle: TextStyle = JetsnackTheme.typography.labelLarge,
enabled: Boolean = true,
content: @Composable RowScope.() -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
Row(
modifier
.clickable(onClick = onClick, indication = null, interactionSource = interactionSource)
.background(if (enabled) backgroundColor else disabledBackgroundColor, shape)
.defaultMinSize(58.dp, 40.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content,
)
}迁移后:
kotlin
// 通过ComponentStyles.kt暴露
object ComponentStyles {
val buttonStyle = Style {
background(colors.brandLight)
shape(shapes.extraLarge)
minWidth(58.dp)
minHeight(40.dp)
textStyle(typography.labelLarge)
disabled {
background(colors.brandSecondary)
}
}
}
@Composable
fun CustomButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
style: Style = Style,
enabled: Boolean = true,
content: @Composable RowScope.() -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
val styleState = rememberUpdatedStyleState(interactionSource) {
it.isEnabled = enabled
}
Row(
modifier
.clickable(onClick = onClick, indication = null, interactionSource = interactionSource)
.styleable(styleState, JetsnackTheme.styles.buttonStyle, style),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content,
)
}Step 4: Validate Changes
步骤4:验证变更
- Build the project. Verify that there are no compilation errors.
- Run your module's screenshot tests.
- Compare visual outputs of the whole app between the previous and updated components. Verify that no visual layout regressions occur.
- 构建项目。确保没有编译错误。
- 运行模块的截图测试。
- 对比更新前后整个应用的视觉输出。确保没有出现视觉布局回归问题。