如何在Jetpack Compose的MaterialTheme中自定义命名颜色?
在Jetpack Compose的MaterialTheme中自定义命名颜色
之前我会在资源文件里定义带名称的颜色(如下方Code A),通过Divider(color = colorResource(R.color.colorGrey))这类方式调用。
阅读官方文档后得知:优先使用主题中的颜色而非硬编码颜色,推荐将应用颜色定义在MaterialTheme中,通过MaterialTheme.colors.primary这类方式访问。
研究了Code B的实现后发现,只能使用primary、primaryVariant等预设命名的颜色,似乎只能覆盖这些预设值。
我希望在MaterialTheme中自定义带名称的颜色,比如通过MaterialTheme.colors.myIcon访问,请问该如何实现?
Code A
<resources> <color name="purple_200">#FFBB86FC</color> <color name="colorGrey">#FF6200EE</color> </resources>
Code B
@Composable fun SoundMeterTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() () -> Unit) { val colors = if (darkTheme) { DarkColorPalette } else { LightColorPalette } MaterialTheme( colors = colors, typography = Typography, shapes = Shapes, content = content ) } private val DarkColorPalette = darkColors( primary = Purple200, primaryVariant = Purple700, secondary = Teal200 ) fun darkColors( primary: Color = Color(0xFFBB86FC), ... ): Colors = Colors( primary, ... )
解决方案
方法1:扩展Material原生Colors类
利用Kotlin的扩展特性,直接给Colors类添加自定义属性,就能通过MaterialTheme.colors.xxx直接访问,实现方式最简单。
定义颜色常量
可以直接定义颜色值,也可以从资源文件读取:// 直接定义颜色 private val MyIconColor = Color(0xFF6200EE) // 从资源读取 @Composable private fun getMyDividerColor() = colorResource(R.color.colorGrey)给Colors类添加扩展属性
// 固定颜色的扩展 val Colors.myIcon: Color @Composable @ReadOnlyComposable get() = MyIconColor // 区分深浅主题的动态颜色扩展 val Colors.myDivider: Color @Composable @ReadOnlyComposable get() = if (isLight) colorResource(R.color.light_divider) else colorResource(R.color.dark_divider)在Compose中调用
Divider(color = MaterialTheme.colors.myDivider) Icon( imageVector = Icons.Filled.Star, contentDescription = "Star icon", tint = MaterialTheme.colors.myIcon )
方法2:自定义主题扩展(支持复杂多主题配置)
如果需要维护一套完全独立的自定义颜色体系,或者需要更灵活的主题切换逻辑,可以通过CompositionLocal实现全局可访问的自定义颜色。
创建自定义颜色数据类
data class CustomColors( val myIcon: Color, val myDivider: Color, val myButtonBg: Color )创建CompositionLocal实例
val LocalCustomColors = compositionLocalOf { // 默认值,实际会被主题中的值覆盖 CustomColors( myIcon = Color.Unspecified, myDivider = Color.Unspecified, myButtonBg = Color.Unspecified ) }修改主题Composable,注入自定义颜色
@Composable fun SoundMeterTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { val materialColors = if (darkTheme) { DarkColorPalette } else { LightColorPalette } // 定义深浅主题对应的自定义颜色 val customColors = if (darkTheme) { CustomColors( myIcon = Color(0xFFBB86FC), myDivider = Color(0xFF424242), myButtonBg = Color(0xFF03DAC6) ) } else { CustomColors( myIcon = Color(0xFF6200EE), myDivider = Color(0xFFE0E0E0), myButtonBg = Color(0xFF03DAC6) ) } // 注入自定义颜色到主题树 CompositionLocalProvider( LocalCustomColors provides customColors ) { MaterialTheme( colors = materialColors, typography = Typography, shapes = Shapes, content = content ) } }添加MaterialTheme扩展属性简化访问
val MaterialTheme.customColors: CustomColors @Composable @ReadOnlyComposable get() = LocalCustomColors.current在Compose中调用
Divider(color = MaterialTheme.customColors.myDivider) Button( onClick = {}, colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.customColors.myButtonBg ) ) { Text("自定义按钮") }
内容的提问来源于stack exchange,提问作者HelloCW
相关产品推荐
相关产品推荐

