在 Compose 中将 XML 主题迁移到 Material 3

在现有应用中引入 Compose 时,您需要迁移 Material XML 主题才能对 Compose 组件使用 MaterialTheme。这意味着应用的主题将会有 2 个可信来源:基于 View 的主题以及 Compose 主题。样式上的任何更改都需要在多处实施。将应用完全迁移到 Compose 后,请移除 XML 主题设置。

您可以使用 Material Theme Builder 工具迁移颜色。

开始从 XML 迁移到 Compose 时,请将主题迁移到 Material 3 Compose 主题。

术语库

术语 定义
MaterialTheme 为 Compose 界面组件提供主题(颜色、排版、形状)的可组合函数。
Shape 一个 Compose 对象,用于为 MaterialTheme 定义自定义组件形状。
Typography 用于为 MaterialTheme 定义自定义文本样式(字体系列、大小、粗细)的 Compose 对象。
Color 用于为 MaterialTheme 定义自定义配色方案的 Compose 对象。
XML 主题 View 系统使用的在 XML 文件中定义的 Android 主题设置系统。

限制

在迁移之前,请注意以下限制:

  • 本指南仅重点介绍如何迁移到 Material 3。如需了解如何从其他设计系统迁移,请参阅 Material 2Compose 中的自定义设计系统
  • 最终目标是完全迁移到 Compose,这样就可以移除 XML 主题设置。本指南介绍了如何迁移,但未介绍如何最终移除 XML 主题设置。

第 1 步:评估设计系统

确定 XML 视图项目中使用的设计系统。 分析迁移路径和必要步骤,以便在 Compose 中将现有设计系统迁移到 Material 3。

第 2 步:确定主题源文件

在 XML 中,您需要写入 ?attr/colorPrimary。在 Compose 中,您可以使用 MaterialTheme.* 访问主题值:

确定并找到主题设置所需的所有 XML 资源和文件:浅色和深色配色方案及限定符、主题、形状、尺寸、排版、样式和其他相关文件。

字符串等资源可按原样重复使用,无需迁移。

第 3 步:迁移颜色

关键原则:XML 使用命名十六进制颜色。 Material 3 使用语义角色(例如 primaryonPrimarysurface)。请停止按十六进制代码命名颜色,而是按角色命名颜色。

示例:

XML 颜色名称 Material 3 角色
colorPrimary primary
colorPrimaryDark/colorPrimaryVariant primaryContainersecondary
colorAccent secondarytertiary
colorOnPrimary onPrimary
android:colorBackground background
colorSurface surface
colorOnSurface onSurface
colorError error
colorOnError onError
colorOutline outline
colorSurfaceVariant surfaceVariant
colorOnSurfaceVariant onSurfaceVariant

将深色和浅色配色方案从 XML 迁移到 Material 3 Compose 中的等效方案。

第 4 步:迁移自定义形状和排版

  • 如果您的应用使用自定义形状:

    1. 在 Compose 代码中,定义一个 Shape 对象来复制 XML 形状定义。
    2. 将此 Shape 对象提供给 MaterialTheme

      如需了解详情,请参阅形状

  • 如果您的应用使用自定义排版:

    1. 在您的 Compose 代码中,定义一个 Typography 对象,以复制 XML 文本样式和字体定义。
    2. 将此 Typography 对象提供给 MaterialTheme

      如需了解详情,请参阅排版

撰写角色 XML 名称
displayLarge TextAppearance.Material3.DisplayLarge
displayMedium TextAppearance.Material3.DisplayMedium
displaySmall TextAppearance.Material3.DisplaySmall
headlineLarge TextAppearance.Material3.HeadlineLarge
headlineMedium TextAppearance.Material3.HeadlineMedium
headlineSmall TextAppearance.Material3.HeadlineSmall
titleLarge TextAppearance.Material3.TitleLarge
titleMedium TextAppearance.Material3.TitleMedium
titleSmall TextAppearance.Material3.TitleSmall
bodyLarge TextAppearance.Material3.BodyLarge
bodyMedium TextAppearance.Material3.BodyMedium
bodySmall TextAppearance.Material3.BodySmall
labelLarge TextAppearance.Material3.LabelLarge
labelMedium TextAppearance.Material3.LabelMedium
labelSmall TextAppearance.Material3.LabelSmall

第 5 步:迁移样式 (styles.xml)

XML 样式 (styles.xml) 系统定义了以下内容的样式和外观: 1. 窗口和对话框的 widget、组件、主题 2. 排版 3. 主题和叠加层 4. 形状

XML 视图和组件会组合多个属性来创建样式。 它们通过两种不同的方式从 styles.xml 设置样式: 1. 在 XML 视图中直接明确地设置“style=@style/...” 2. 间接且隐式地为组件设置样式,作为较大主题 (theme.xml) 的一部分

Compose 中没有与样式直接等效的概念,而是将样式作为参数传递给可组合项,在 AppTheme 中定义样式,或者通过创建具有已定义样式的分层可重用可组合项变体来定义样式。

提供根据样式和基本组件命名的单独 @Composable 函数,以表明这些组件在样式和使用情形方面的差异。

  • 模式:如果 XML 元素使用自定义样式(例如 style="@style/MyPrimaryButton"),请勿尝试内嵌复制该样式。而是建议创建特定的可组合项。
  • 示例
    • XML<Button style="@style/MyPrimaryButton" ... />
    • 撰写: MyPrimaryButton(onClick = { ... })
  • 常见属性组:如果样式设置了常见的修饰符(例如内边距 + 高度),请将它们提取到可读的扩展属性或共享的 Modifier 变量中。

常见示例

XML 撰写
Theme.MaterialComponents.* MaterialTheme(colorScheme, typography, shapes) { }
TextAppearance.Material3.BodyMedium TextStyle(...)Typography(bodyMedium = ...) 中定义
ShapeAppearance.*.SmallComponent Shapes(small = RoundedCornerShape(X.dp))
Widget.MaterialComponents.Button Button(colors = ButtonDefaults.buttonColors(...))
Widget.MaterialComponents.CardView Card(shape=..., elevation=..., colors=...)
Widget.*.TextInputLayout.OutlinedBox OutlinedTextField(colors = OutlinedTextFieldDefaults.colors(...))
Widget.*.Chip.Filter FilterChip(colors = FilterChipDefaults.filterChipColors(...))
Widget.*.Toolbar.Primary TopAppBar(colors = TopAppBarDefaults.topAppBarColors(...))
Widget.*.FloatingActionButton FloatingActionButton(containerColor = ...)
backgroundTint containerColor(在 ComponentDefaults.ComponentColors() 中)
android:textColor contentColor(在 ComponentDefaults.ComponentColors() 中)
cornerRadius shape = RoundedCornerShape(X.dp)
android:elevation elevation = ComponentDefaults.elevation(defaultElevation = X.dp)
android:padding contentPadding = PaddingValues(...)Modifier.padding()
android:minHeight Modifier.heightIn(min = X.dp)
strokeColor + strokeWidth border = BorderStroke(width, color)
android:textSize fontSize = X.sp(在 TextStyle 中)

第 6 步:验证主题迁移

始终使用原始 XML 主题中的现有主题值作为 Compose 中新 Material 主题的真实来源。在迁移期间,切勿创建新的主题值,以保持品牌一致性并避免出现视觉回归。

验证所有新的 Compose 主题值是否与现有的 XML 值一致。 请勿对任何迁移的值进行硬编码。