要实现背景、弹框、按钮、Switch 和 Checkbox 等组件在 View 和 Compose 中的完全一致,需要系统性的主题配置。以下是完整解决方案:
res/values/themes.xml
和 res/values-night/themes.xml
中:
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight">
- "android:windowBackground"
>@color/background
- "colorSurface"
>@color/surface
- "materialButtonStyle">@style/Widget.MyApp.Button
- "checkboxStyle">@style/Widget.MyApp.CompoundButton.CheckBox
- "switchStyle">@style/Widget.MyApp.CompoundButton.Switch
- "dialogCornerRadius">8dp
- "dialogBackground">@drawable/bg_dialog
style>
<style name="Widget.MyApp.Button" parent="Widget.MaterialComponents.Button">
- "backgroundTint"
>@color/button_background
- "cornerRadius"
>4dp
style>
<style name="Widget.MyApp.CompoundButton.CheckBox" parent="Widget.MaterialComponents.CompoundButton.CheckBox">
- "buttonTint"
>@color/checkbox_tint
style>
<style name="Widget.MyApp.CompoundButton.Switch" parent="Widget.MaterialComponents.CompoundButton.Switch">
- "useMaterialThemeColors"
>false
- "thumbTint"
>@color/switch_thumb
- "trackTint">@color/switch_track
style>
@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (darkTheme) {
// 深色主题颜色
darkColors(
primary = Color(0xFFBB86FC),
secondary = Color(0xFF03DAC6),
surface = colorResource(R.color.surface),
background = colorResource(R.color.background),
onPrimary = Color.Black,
onSecondary = Color.Black
)
} else {
// 浅色主题颜色
lightColors(
primary = Color(0xFF6200EE),
secondary = Color(0xFF03DAC6),
surface = colorResource(R.color.surface),
background = colorResource(R.color.background),
onPrimary = Color.White,
onSecondary = Color.Black
)
}
val shapes = Shapes(
small = RoundedCornerShape(4.dp),
medium = RoundedCornerShape(8.dp),
large = RoundedCornerShape(12.dp)
)
MaterialTheme(
colors = colors,
shapes = shapes,
typography = Typography,
content = content
)
// 统一组件样式
CompositionLocalProvider(
LocalMinimumInteractiveComponentEnforcement provides false
) {
ProvideTextStyle(
value = MaterialTheme.typography.body1,
content = content
)
}
}
传统 View 弹框:
AlertDialog.Builder(this)
.setView(R.layout.custom_dialog)
.create()
.apply {
window?.setBackgroundDrawableResource(R.drawable.bg_dialog)
}
Compose 弹框:
@Composable
fun MyAlertDialog() {
AlertDialog(
onDismissRequest = { /*...*/ },
modifier = Modifier.background(
color = MaterialTheme.colors.surface,
shape = MaterialTheme.shapes.medium
),
properties = DialogProperties()
) {
// 弹框内容
}
}
传统 View 按钮:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View 按钮"
style="@style/Widget.MyApp.Button"/>
Compose 按钮:
Button(
onClick = { /*...*/ },
shape = MaterialTheme.shapes.small,
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.colors.primary,
contentColor = MaterialTheme.colors.onPrimary
)
) {
Text("Compose 按钮")
}
传统 View:
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.MyApp.CompoundButton.CheckBox"/>
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.MyApp.CompoundButton.Switch"/>
Compose:
// Checkbox
Checkbox(
checked = checked,
onCheckedChange = { /*...*/ },
colors = CheckboxDefaults.colors(
checkedColor = MaterialTheme.colors.primary,
uncheckedColor = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
checkmarkColor = MaterialTheme.colors.onPrimary
)
)
// Switch
Switch(
checked = checked,
onCheckedChange = { /*...*/ },
colors = SwitchDefaults.colors(
checkedThumbColor = MaterialTheme.colors.primary,
checkedTrackColor = MaterialTheme.colors.primary.copy(alpha = 0.5f),
uncheckedThumbColor = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
uncheckedTrackColor = MaterialTheme.colors.onSurface.copy(alpha = 0.3f)
)
)
在 res/values/colors.xml
和 res/values-night/colors.xml
中定义所有颜色:
<color name="primary">#6200EEcolor>
<color name="primary_dark">#3700B3color>
<color name="secondary">#03DAC6color>
<color name="background">#FAFAFAcolor>
<color name="surface">#FFFFFFcolor>
<color name="button_background">#6200EEcolor>
<color name="switch_thumb">#FFFFFFcolor>
<color name="switch_track">#C4C4C4color>
<color name="primary">#BB86FCcolor>
<color name="primary_dark">#3700B3color>
<color name="secondary">#03DAC6color>
<color name="background">#121212color>
<color name="surface">#1E1E1Ecolor>
<color name="button_background">#BB86FCcolor>
<color name="switch_thumb">#BB86FCcolor>
<color name="switch_track">#646464color>
为方便在 Compose 中使用 View 定义的颜色:
@Composable
fun ViewColor(@ColorRes id: Int): Color {
return colorResource(id = id)
}
// 使用示例
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = ViewColor(R.color.button_background)
)
) {
Text("按钮")
}
通过以上配置,你可以确保项目中 View 和 Compose 的所有组件在浅色和深色模式下保持完全一致的视觉风格。