Compose对Theme管理

138 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

Screen Shot 2022-11-29 at 7.27.43 PM.png

大家应该对theme已经很熟悉了,所谓Theme就是不同的style,例如颜色,item的形状,字体等方面。在Compose里面Theme也是针对这几个方面进行配置。看看MaterialTheme的定义:

fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
)

在Compose里面,当你创建好工程的时候对于app独有的theme对象就有了。

fun ComposeExampleTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
    val colors = if (darkTheme) {
        DarkColorPalette
    } else {
        LightColorPalette
    }

    MaterialTheme(
        colors = colors,
        typography = Typography,
        shapes = Shapes,
        content = content
    )
}

在创建app的时候会产生类似这样的compoosable函数,color是我们在app的代码里面自定义的:

private val DarkColorPalette = darkColors(
    primary = Purple200,
    primaryVariant = Purple700,
    secondary = Teal200
)

private val LightColorPalette = lightColors(
    primary = Purple500,
    primaryVariant = Purple700,
    secondary = Teal200

    /* Other default colors to override
    background = Color.White,
    surface = Color.White,
    onPrimary = Color.White,
    onSecondary = Color.Black,
    onBackground = Color.Black,
    onSurface = Color.Black,
    */
)

我们如果要改主题的颜色,那么相应的去换自定义的颜色就可以了。那需要怎么使用呢?

color = MaterialTheme.colors.primary

那现在会使用了,应该怎么切换theme呢?这个就要充分利用Composable函数了。如下示例代码:

var isDark by remember {
    mutableStateOf(false)
}
ComposeExampleTheme(darkTheme = isDark) {
    // A surface container using the 'background' color from the theme
    Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
        Column() {
            Box(modifier = Modifier
                .fillMaxSize()
                .wrapContentSize()
                .weight(1f)
                .border(BorderStroke(width = 2.dp, color = MaterialTheme.colors.primary))){
                Text(text = "Hi,Compose!")
            }
            Button(onClick = { isDark = !isDark}) {
                Text(text = "Change theme")
            }
        }

    }
}

我们首先定义一个mutableState变量,然后在button onclick的时候改变这个值就可以切换相应的theme了。当state值变化的时候会触发composable函数的重组,从而达到切换theme的效果。需要说明的是这个一定要是一个state变量,这样才能触发composable函数。这个比之前切换theme简单多了。例子的效果如下:

change_theme.gif

那大家可能还有一些疑问,如果在MaterailTheme里面没有我想要的颜色怎么办呢?这个Compose也想到了,可以使用自定义的theme:

  1. 首先定义一个类来表述自定义的color:
class LocalColor(
    var color1:Color = Color.Unspecified,
    var color2:Color = Color.Unspecified,
    var color3:Color = Color.Unspecified,

)
  1. 定义全局变量:
val localColorTheme = staticCompositionLocalOf { LocalColor() }
  1. 自定义不同theme下面的值,这里简单写了几个值:
val localDarkTheme = LocalColor(color1 = Color.White, color2 = Color.Red, color3 = Color.Gray)
val localLightTheme = LocalColor(color1 = Color.Black, color2 = Color.Green, color3 = Color.Blue)
  1. 使其生效,在定义theme的地方使用provider将其定义成类似一个全局变量,这样在其他使用到这个theme的地方都可以使用自定义的theme了。
val localColor = if(darkTheme) localDarkTheme else localLightTheme
CompositionLocalProvider(localColorTheme provides localColor){
    MaterialTheme(
        colors = colors,
        typography = Typography,
        shapes = Shapes,
        content = content
    )
}

上面举了自定义color的还可以自定义其他的资源。应用theme只要在根composable函数上面应用就可以了。