整个应用(包括 View 和 Compose 部分)的浅色/深色模式保持一致。以下是完整的解决方案:
全局配置方案
1. 基础主题设置
在 res/values/themes.xml
和 res/values-night/themes.xml
中定义统一的主题:
xml
<!-- values/themes.xml -->
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight">
<!-- 浅色主题颜色 -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorSecondary">@color/teal_200</item>
</style>
<!-- values-night/themes.xml -->
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight">
<!-- 深色主题颜色 -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_500</item>
<item name="colorSecondary">@color/teal_200</item>
</style>
2. Compose 主题适配器
创建 Compose 主题与 XML 主题的桥梁:
kotlin
// Theme.kt
@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val context = LocalContext.current
val colors = if (darkTheme) {
// 从 XML 资源获取颜色
val primaryColor = context.getColor(R.color.purple_200)
val primaryVariantColor = context.getColor(R.color.purple_500)
val secondaryColor = context.getColor(R.color.teal_200)
darkColors(
primary = Color(primaryColor),
primaryVariant = Color(primaryVariantColor),
secondary = Color(secondaryColor)
)
} else {
val primaryColor = context.getColor(R.color.purple_500)
val primaryVariantColor = context.getColor(R.color.purple_700)
val secondaryColor = context.getColor(R.color.teal_200)
lightColors(
primary = Color(primaryColor),
primaryVariant = Color(primaryVariantColor),
secondary = Color(secondaryColor)
)
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}
3. 全局主题切换控制
在 Application 类中统一管理主题:
kotlin
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// 设置默认主题模式
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
companion object {
fun setDarkMode(enabled: Boolean) {
AppCompatDelegate.setDefaultNightMode(
if (enabled) AppCompatDelegate.MODE_NIGHT_YES
else AppCompatDelegate.MODE_NIGHT_NO
)
}
}
}
实际使用示例
传统 View Activity
kotlin
class LegacyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 会自动应用 themes.xml 中定义的主题
setContentView(R.layout.activity_legacy)
}
}
Compose Activity
kotlin
class ComposeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
// 你的 Compose 内容
Surface {
Text("这是 Compose 界面")
}
}
}
}
}
迁移过程中的注意事项
-
混合 Activity 处理:
- 对于同时包含 View 和 Compose 的 Activity,使用
ComposeView
桥接
xml<!-- activity_mixed.xml --> <LinearLayout> <TextView android:text="传统 View"/> <androidx.compose.ui.platform.ComposeView android:id="@+id/compose_view" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
- 对于同时包含 View 和 Compose 的 Activity,使用
-
颜色资源统一:
- 所有颜色定义在
res/values/colors.xml
和res/values-night/colors.xml
中 - Compose 通过
colorResource(id = R.color.your_color)
使用
- 所有颜色定义在
-
主题切换同步:
- 使用
AppCompatDelegate.setDefaultNightMode()
切换时,所有 Activity 都会自动重建并应用新主题
- 使用
通过这种方式,你可以确保项目中前期使用 View 的 Activity 和后期使用 Compose 的 Activity 在浅色/深色模式下保持完全一致的视觉风格。