在 Composable 函数之外引用或枚举 Jetpack Compose MaterialTheme 主题颜色

Referencing or enumerating Jetpack Compose MaterialTheme theme colors outside Composable function

我希望向 @Composable 函数提供一个参数,该函数接受一种颜色,但只能来自一个离散列表。

大致如下:

enum class SpecialColor(val color: Color) {
    ALPHA(MaterialTheme.colors.onSurface),
    BETA(MaterialTheme.colors.onSecondary)
}

@Composable
fun ColorSample(specialColor: SpecialColor) {
    Box(
        modifier = Modifier
            .width(100.dp)
            .height(100.dp)
            .background(specialColor.color)
    )
}

@Preview
@Composable
fun PreviewSample() {
    CustomTheme {
        ColorSample(specialColor = SpecialColor.ALPHA)
    }
}

由于以上是在可组合上下文之外引用 MaterialTheme.colors,因此出现以下错误:

@Composable invocations can only happen from the context of a @Composable function

如果颜色是直接引用的,而不是通过 Material 主题,颜色将无法正确更新 light/dark 模式。

一种策略可能是将枚举值映射到@Composable 函数本身内的Material主题颜色。但这很麻烦、笨重,并且不能很好地扩展 - 想象一个更长的颜色列表和相同的 SpecialColor 列表需要被重复用于许多功能。

另一种策略可能是直接使用 LocalContentColor 或类似工具修改主题颜色,但这太宽泛了,而且会改变目标功能以外的颜色。

从实用程序 @Composable 函数返回颜色也不是一个选项,因为 @Composable 函数没有 return 值。

所以...
关于如何提供 Compose Material 颜色枚举列表之一作为参数的任何想法?
以一种干净且可扩展的方式很好地扩展?

事实并非如此:

@Composable functions don't have return values.

您可以使用 return 类型注释函数,甚至可以使用 @Composable 注释 getter 属性。例如 this 是 Material 主题源代码的一部分。

定义颜色的方法如下:

enum class SpecialColor {
    ALPHA,
    BETA,
    ;

    val color: Color
        @Composable
        @ReadOnlyComposable
        get() = when(this) {
            ALPHA -> MaterialTheme.colors.onSurface
            BETA -> MaterialTheme.colors.onSecondary
        }
}