如何在 Android Jetpack Compose 中向 MaterialTheme 添加额外的颜色?

问题描述 投票:0回答:8

Android Jetpack Compose Colors 类包含一组可以用于实现材质主题应用程序的颜色类型。如果我的应用程序主题需要一些额外的颜色类型,我如何添加这些额外的颜色,以便可以通过 MaterialTheme 对象使用它们?

android android-jetpack android-jetpack-compose
8个回答
40
投票

对 Valeriy Katkov 的答案稍加改动

在某些版本的android studio中,以下代码将不起作用

@Composable
val Colors.myExtraColor: Color
    get() = if (isLight) Color.Red else Color.Green

@Composable
fun ExtraColorExample() {
    Text(
        text = "test",
        color = MaterialTheme.colors.myExtraColor // <-- the newly added color
    )
}

会显示错误

此注解不适用于目标'顶级属性 没有支持场或代表'

要解决这个问题,可以这样写

@get:Composable
val Colors.myExtraColor: Color
    get() = if (isLight) Color.Red else Color.Green

或者

val Colors.myExtraColor: Color
    @Composable
    get() = if (isLight) Color.Red else Color.Green

我发现这个错误的版本

Android Studio Arctic Fox | 2020.3.1 Canary 12
Build #AI-203.7148.57.2031.7226969, built on March 23, 2021
Runtime version: 11.0.8+10-b944.6842174 amd64
VM: OpenJDK 64-Bit Server VM by N/A
Windows 10 10.0

25
投票

基本上有两种方法:

最简单的方法是仅创建扩展属性来对颜色进行硬编码。如果您不想支持多个主题或亮/暗模式,这也可以。

如果您想将颜色正确地融入主题,您可以阅读我的文章,因为这里内联有点长:https://gustav-karlsson.medium.com/extending-the-jetpack-compose -材质主题与更多颜色-e1b849390d50

但简而言之,步骤是:

  • 创建您自己的
    MyColors
    类,其中包含对
    Colors
    以及新颜色的引用。
  • 创建一个
    CompositionLocal
    来保存
    MyColor
    实例。
  • 创建您的主题并将
    MaterialTheme
    包装在
    CompositionLocalProvider
    中,其中
    CompositionLocal
    提供
    MyColors
    。确保还将
    Colors
    中的
    MyColors
    实例分配给
    MaterialTheme
  • MaterialTheme
    上创建一个扩展属性,引用持有
    CompositionLocal
    MyColors
    。这就是您引用新颜色的方式。

这将允许您向主题引入新的颜色,这些颜色将随着主题的变化而动态更新。


9
投票

对于 Material3,我必须扩展

androidx.compose.material3.ColorScheme
对象,因为
MaterialTheme.colors
不存在。

val ColorScheme.successContainer: Color @Composable
    get() = if (!isSystemInDarkTheme()) Color(0xFFd6ffe0) else Color(0xFF269300)

Text(
    text = "Hello World",
    modifier = Modifier.background(color = MaterialTheme.colorScheme.successContainer)
)

7
投票

延长
Colors
课程

您可以轻松地将 扩展属性 添加到

Colors
类,以便可以通过应用程序中的任何
Colors
对象使用它。

@Composable
val Colors.myExtraColor: Color
    get() = if (isLight) Color.Red else Color.Green

@Composable
fun ExtraColorExample() {
    Text(
        text = "test",
        color = MaterialTheme.colors.myExtraColor // <-- the newly added color
    )
}

撰写文档中也有一个示例,请参阅扩展材质颜色

指定内容 alpha

如果您缺少的颜色与现有颜色的不同之处仅在于 Alpha,并且该颜色的目的是更改内容优先级,则无需向主题添加其他颜色。您可以通过为 LocalContentAlpha 提供值来指定层次结构的内容 alpha。

CompositionLocalProvider(
    LocalContentAlpha provides ContentAlpha.medium,
    LocalContentColor provides MaterialTheme.colors.onSurface
) {
    // this text is displayed using ContentAlpha.medium
    // and MaterialTheme.colors.onSurface color
    Text("Hello world!") 
}

请参阅Content Alpha文档了解更多详细信息。

Jetpack Compose Theming
codelab 中还有 Content Alpha 部分。


2
投票

在我的例子中,主题组件从保存的设置中获取其参数,即应用程序主题独立于设备主题。因此,当前的答案对我不起作用。

我的实现与

Material 3
相关,并且直接取决于传递的参数。

Color.kt

package com.my.app.theme

import androidx.compose.ui.graphics.Color

val SuccessLightColor = Color(0xFF436915)
val SuccessLightContainerColor = Color(0xFFC2F18D)

val SuccessDarkColor = Color(0xFFA7D474)
val SuccessDarkContainerColor = Color(0xFF2D5000)

Theme.kt

package com.my.app.theme

import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext

private val DarkColorScheme = darkColorScheme()

private val LightColorScheme = lightColorScheme()

var successColorSchemeColor by mutableStateOf(SuccessLightColor)
var successContainerColorSchemeColor by mutableStateOf(SuccessLightColor)

@Suppress("unused")
var ColorScheme.success: Color
    get() = successColorSchemeColor
    set(value) {
        successColorSchemeColor = value
    }

@Suppress("unused")
var ColorScheme.successContainer: Color
    get() = successContainerColorSchemeColor
    set(value) {
        successContainerColorSchemeColor = value
    }


@Composable
fun Theme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = true,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }
        darkTheme -> DarkColorScheme
        else -> LightColorScheme
    }

    colorScheme.success = if (darkTheme) {
        SuccessDarkColor
    } else {
        SuccessLightColor
    }

    colorScheme.successContainer = if (darkTheme) {
        SuccessDarkContainerColor
    } else {
        SuccessLightContainerColor
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = Typography,
        content = content
    )
}

使用案例:

Box(
    modifier = Modifier
        .size(128.dp)
        .background(
            color = MaterialTheme.colorScheme.successContainer
        )
)

1
投票

“CompositionLocal”答案是正确的,但可能不太容易理解。

youtube 上的 Android 开发者发送了一个视频:“Compose by example”。 https://www.youtube.com/watch?v=DDd6IOlH3io on 6:28/22:07 介绍了这个用法。

这是我学习这部分的示例代码,供大家复制:

定义主题:

val Purple200 = Color(0xFFBB86FC)
val Purple500 = Color(0xFF6200EE)
val Purple700 = Color(0xFF3700B3)
val Teal200 = Color(0xFF03DAC5)

val yellow200 = Color(0xffffeb46)
val yellow400 = Color(0xffffc000)
val yellow500 = Color(0xffffde03)
val yellowDarkPrimary = Color(0xff242316)
val yellowLightPrimary = Color(0xffd4d3f6)


class RabbitColorPalette(
    val raFirstColor: Color,
    val raSecColor: Color,
    val raOnFirstColor: Color,
    val raOnSecColor: Color
    )

val rabbitPurple = RabbitColorPalette(Purple200,Purple500,Purple700,Teal200)
val rabbitYellow = RabbitColorPalette(yellow200,yellow400,yellow500,yellowDarkPrimary)

val rabbitColors = compositionLocalOf<RabbitColorPalette>{
    rabbitPurple
}

@Composable
fun RabbitThemePink(
    content: @Composable() () -> Unit
) {
    val colors = rabbitPurple
    CompositionLocalProvider(rabbitColors provides colors){
        MaterialTheme(
            typography = Typography,
            shapes = Shapes,
            content = content
        )
    }
}

object RabbitTheme{
    val colors: RabbitColorPalette
        @Composable get() = rabbitColors.current
}

@Composable
fun RabbitThemeYellow(
    content: @Composable() () -> Unit
) {
    val colors = rabbitYellow
    CompositionLocalProvider(rabbitColors provides colors){
        MaterialTheme(
            typography = Typography,
            shapes = Shapes,
            content = content
        )
    }
} 

用法

class RabbitThemeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            RabbitThemePink {
                SampleLayout()
            }
        }
    }

    @Composable
    fun SampleLayout() {
        Column {
            Text(text = "sample", modifier = Modifier.background(color = RabbitTheme.colors.raFirstColor))
            Text(text = "des", modifier = Modifier.background(color = RabbitTheme.colors.raSecColor))
        }
    }

    @Preview
    @Composable
    fun ConstraintLayoutContentPinkPreview() {
        RabbitThemePink {
            SampleLayout()
        }
    }

    @Preview
    @Composable
    fun ConstraintLayoutContentYellowPreview() {
        RabbitThemeYellow {
            SampleLayout()
        }
    }
}

1
投票

这里的所有答案似乎要么有点过时,要么过于复杂。我发现简短而有用的是这个答案

所有学分归原作者@Thales Isidoro


0
投票

像下面的代码一样创建自定义颜色并使用 Materialtheme 设置颜色

    val ColorScheme.myCustomColor: Color
        @Composable
        get() = if (isSystemInDarkTheme()) Color.Green else Color.Red
    @Composable
    fun Greeting(name: String, modifier: Modifier = Modifier) {
        Text(
            text = "Hello $name!",
            modifier = modifier,
            color = MaterialTheme.colorScheme.myCustomColor //Custom color
        )
    }
© www.soinside.com 2019 - 2024. All rights reserved.