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

Posted 乐翁龙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Compose -- Theme主题,还怕你的App不够花里胡哨么?相关的知识,希望对你有一定的参考价值。

Compose主题

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

需求一览

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

默认的主题

比如我们的工程名叫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
        )
    

预览效果如下所示:

实现需求

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

 setContent 
     val themeName = remember 
         mutableStateOf("blue")
     

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

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

Colors属性不够用?

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

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

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

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

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

以上是关于Compose -- Theme主题,还怕你的App不够花里胡哨么?的主要内容,如果未能解决你的问题,请参考以下文章

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

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

拥有了 Compose -- Theme主题,还怕你的App不够花里胡哨么?

[技术干货] Zabbix创建自定义主题(theme)

使用Material Design 创建App翻译系列----材料主题的使用(Using Material Theme)

Jetpack Compose“onSurface”颜色不起作用