Compose -- Theme【主题】,还怕你的App不够花里胡哨么?

文章目录

  • Compose主题
    • 需求一览
    • 默认的主题
    • 自定义主题
    • 实现需求
    • Colors属性不够用?

Compose主题

Compose提供了系统化的方法来帮助我们自定义主题,这让我们在实现暗黑主题以及其他颜色主题的时候非常非常的方便。

需求一览

这节的需求很简单,我们的App需要有蓝,红,绿,黄四种主题色,在点击tab的时候分别切换不同的主题色,大致效果如下所示。
GIF 2021-6-4 19-34-09.gif

默认的主题

比如我们的工程名叫ComposeComing,那么工程建好后默认的Activity中会有如下代码:

setContent {
     
    ComposeComingTheme {
     

        Surface(color = MaterialTheme.colors.background) {
     
            
        }
    }
}

上面有两处代码很可疑:

  • ComposeComingTheme
  • MaterialTheme.colors.background

首先这个 ComposeComingTheme() 函数我们点进去看下,你会发现该组合函数在 包名.ui.theme 文件夹下的 Theme.kt 文件中:

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

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

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

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

通过上述代码,我们可以了解到:ComposeComingTheme 该组合函数在 MaterialTheme 上构建而成,MaterialTheme由colors、typography、shapes属性组成。然后该组合函数默认根据系统 是否是暗黑主题颜色属性 进行了不同的定义。如果是暗黑主题使用DarkColorPalette,否则使用LightColorPalette。darkColors和lightColors都继承自Colors,并有相关的默认颜色值。所以我们的需求-自定义不同的主题颜色可以在这里进行突破了。

Colors中的所有可配的值如下所示:

@Stable
class Colors(
    primary: Color,
    primaryVariant: Color,
    secondary: Color,
    secondaryVariant: Color,
    background: Color,
    surface: Color,
    error: Color,
    onPrimary: Color,
    onSecondary: Color,
    onBackground: Color,
    onSurface: Color,
    onError: Color,
    isLight: Boolean
)

而 MaterialTheme.colors.background 中最终调用的就是相关主题中设置的Colors的 background 属性值。

自定义主题

接下来我们根据需求进行主题的自定义,首先给大家点颜色看看,在ui.theme文件夹下的Color.kt文件中添加如下颜色:

val blue = Color(0xFF579DFD)
val red = Color(0xFFEB685E)
val green = Color(0xFF27BA6A)
val yellow = Color(0xFFFFCB1F)

然后在ui.theme文件夹下的Theme.kt文件中自定义主题,在这里我们统一使用了lightColors,然后根据传递进来的主题的名称将primary属性设置为了不同的颜色,如下所示:

@Composable
fun MyAppTheme(
    themeName: String = "blue",
    content: @Composable() () -> Unit
) {
     

    val colors = when (themeName) {
     
        "red" -> lightColors(primary = red)
        "green" -> lightColors(primary = green)
        "yellow" -> lightColors(primary = yellow)
        else -> lightColors(primary = blue)
    }

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

这样我们主题就已经定义好了,虽然只有primary属性会根据不同主题变化,但是这足够我们演示了。

接下来是TabRow的实现,我们将TabRow的背景颜色 backgroundColor 设置为刚定义的 primary 的颜色,点击不同tab的时候设置不同的主题,并将点击事件提升到上层处理,代码如下所示,:

@Composable
fun MyTabRow(
    onTabItemClick: (name: String) -> Unit,
    indexDefault: Int = 0
) {
     

    val indexState = remember {
     
        mutableStateOf(indexDefault)
    }

    val colorsTab = arrayOf("blue", "red", "green", "yellow")

    TabRow(
        selectedTabIndex = indexState.value,
        modifier = Modifier
            .fillMaxWidth()
            .height(46.dp),
        backgroundColor = MaterialTheme.colors.primary
    ) {
     
        for ((index, name) in colorsTab.withIndex()) {
     
            Tab(
                selected = index == indexState.value,
                onClick = {
     
                    indexState.value = index
                    onTabItemClick(colorsTab[index])
                },
                modifier = Modifier.fillMaxHeight(),

                ) {
     
                Text(
                    text = name,
                    modifier = Modifier
                        .fillMaxWidth()
                        .wrapContentHeight(),
                    textAlign = TextAlign.Center
                )
            }
        }
    }
}

先来预览下吧,我们在自定的主题MyAppTheme中组合MyTabRow,然后给定相关的主题颜色,这里默认预览红色和绿色的主题:

@Preview(showBackground = true)
@Composable
fun RedThemePreview() {
     
    MyAppTheme(themeName = "red") {
     
        MyTabRow(
            onTabItemClick = {
     },
            indexDefault = 1
        )
    }
}

@Preview(showBackground = true)
@Composable
fun GreenThemePreview() {
     
    MyAppTheme(themeName = "green") {
     
        MyTabRow(
            onTabItemClick = {
     },
            indexDefault = 2
        )
    }
}

预览效果如下所示:
Compose -- Theme【主题】,还怕你的App不够花里胡哨么?_第1张图片

实现需求

预览图没有问题,接下来就是整体的实现了,反正就一点 – 数据驱动,视图自响应,在onCreate()函数中:

 setContent {
     
     val themeName = remember {
     
         mutableStateOf("blue")
     }

     MyAppTheme(themeName = themeName.value) {
     
         Column {
     
             MyTabRow(onTabItemClick = {
     
                 themeName.value = it
             })
         }
     }
 }

这样,我们点击不同tab的时候,改变themeName的值,MyAppTheme会自动根据相应的值进行主题的切换,是不是就达到了如下效果呢:
GIF 2021-6-4 19-34-09.gif

Colors属性不够用?

上述需求实在是太简单了,但是实际开发中我们可能有很多种地方都定义了不同的颜色,而Colors中只提供了12个相关颜色的定义,不够用啊!!!

那怎么办呢?扩展,字面意义上的扩展,同时也是kotlin中的扩展。直接给Colors扩展相关的属性:

val Colors.myTabRowBackground: Color
    @Composable get() = if (isLight) red else blue

但是这种方式明显有弊端,就是只能根据是否是暗黑主题进行颜色的配置,无法支持到我们上述的那么多种主题,而且也比较麻烦。

而且我查遍了全网也没有见到使用var来进行属性扩展的示例,难道是不支持么?扔物线的视频让我自己研究,其他培训机构的老师讲到这里直接卡壳了。我需要给这个扩展的属性进行赋值和取值的操作,求指点。

你可能感兴趣的:(Jetpack-Compose,新星计划,Compose,Theme,主题,自定义主题)