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

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

您可以使用 Material 主题构建器工具迁移颜色。

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

术语表

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

限制

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

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

第 1 步:评估设计体系

确定 XML View 项目中使用的是哪种设计体系。分析迁移路径以及在 Compose 中将现有设计系统迁移到 Material 3 的必要步骤。

第 2 步:确定主题背景源文件

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

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

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

第 3 步:迁移颜色

关键原则:XML 使用命名的十六进制颜色。 Material 3 使用语义角色(例如 primary、onPrimary、surface)。请停止按十六进制代码命名颜色,而应按其角色命名。

示例:

XML 颜色名称 Material 3 角色
colorPrimary primary
colorPrimaryDark/colorPrimaryVariant primaryContainer 或 secondary
colorAccent secondary 或 tertiary
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 代码中,定义一个 Shapes 对象来复制 XML 形状定义。
    2. 将此 Shapes 对象提供给 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. 窗口和对话框的小组件、组件、主题
  2. 排版
  3. 主题和叠加层
  4. 形状

XML 视图和组件会组合多个属性来创建样式。 它们通过两种不同的方式从 styles.xml 设置其样式:

  1. 直接在 XML 视图中明确设置“style="@style/…"”
  2. 作为较大主题 (theme.xml) 的一部分,为组件间接和隐式设置样式

样式在 Compose 中没有直接等效项,而是通过以下方式传递:作为可组合项的参数或修饰符,使用 AppTheme 中定义的全新实验性 Styles API,或使用定义的样式创建分层的可重用可组合项变体。

提供根据样式和基本组件命名的单独 @Composable 可组合函数,以表示这些组件的样式和应用场景差异。

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

常见示例

XML 写邮件
Theme.Material3.* MaterialTheme(colorScheme, typography, shapes) { }
TextAppearance.Material3.BodyMedium TextStyle(...) 在 Typography(bodyMedium = ...) 中定义
ShapeAppearance.*.SmallComponent Shapes(small = RoundedCornerShape(X.dp))
Widget.Material3.Button Button(colors = ButtonDefaults.buttonColors(...))
Widget.Material3.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 ComponentDefaults.ComponentColors() 中的 containerColor
android:textColor ComponentDefaults.ComponentColors() 中的 contentColor
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 TextStyle 中的 fontSize = X.sp

第 6 步:验证主题迁移

始终使用原始 XML 主题中的现有主题值作为 Compose 中新 Material 主题设置的可信来源。在迁移过程中,切勿创造新的主题值,以保持品牌一致性并避免视觉效果退化。

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