如何在Jetpack Compose中引用主题属性?

23

所以在当前的安卓开发中,如果我们需要引用主题中的一组颜色,我们可以简单地这样做:(在布局xml中)

....
    <TextView
        ...
        android:textColor="?attr/colorPrimary"
        .../>
....

如果我在主题中设置了蓝色,那么上面的文本视图中将显示该颜色。

我想知道如何在 Jetpack Compose 中实现相同的效果。在 Compose 中,我们可以这样做:

MaterialTheme(...) {
    Column {
        Text(
            ...
            textStyle = TextStyle(color = ????) // How to I reference to the theme?
        )
    }
}

1
如果您正在使用Material Design Components,您可以使用Accompanist在Compose中利用您的主题资源 - CommonsWare
5个回答

23

你可以使用类似以下方式的方法:

Text(text = "....",
     style = TextStyle(color = MaterialTheme.colors.primary))

21
如果我想引用尺寸属性,例如 android.R.attr.actionBarSize,该怎么办? - Sơn Phan
@SơnPhan,你找到解决方案了吗? - Akbolat SSS
实际上我没有找到关于这个的任何信息,所以在这里提问了。 - Akbolat SSS

5
获取属性颜色,我使用这个可组合函数:
@Composable
fun getColor(color: Int): Color {
    return colorResource(LocalContext.current.getColorFromAttrs(color).resourceId)
}

fun Context.getColorFromAttrs(attr: Int): TypedValue {
    return TypedValue().apply {
        theme.resolveAttribute(attr, this, true)
    }
}

用法:

val color: Color = getColor(R.attr.colorText)

不错,但我更喜欢更简洁的版本:@Composable @ReadOnlyComposable fun colorAttribute(attrColor: Int) = colorResource(TypedValue().apply { LocalContext.current.theme.resolveAttribute(attrColor, this, true) }.resourceId) - maatik5

4

Compose提供了基于Material颜色规范的ColorPalette,用于生成应用程序主题。它提供了lightColorPalettedarkColorPalette,用于分别定义浅色和深色模式的主题。

val lightThemeColors = lightColorPalette(
    primary = Color(0xFFFFFFFF),
    primaryVariant = Color(0xFFFFFFFF),
    onPrimary = Color.Black,
    secondary = Color.Transparent,
    onSecondary = Color.White,
    background = Color.White,
    onBackground = Color(0xFF212121),
    surface = Color.White,
    onSurface = Color(0xFF212121),
    error = Color.Red,
    onError = Color.White
)
val darkThemeColors = darkColorPalette(
    primary = Color(0xFF000000),
    primaryVariant = Color(0xFF000000),
    onPrimary = Color.White,
    secondary = Color.White,
    onSecondary = Color.White,
    surface = Color(0xFF212121),
    background = Color(0xFF212121),
    onBackground = Color.White,
    onSurface = Color.White,
    error = Color.Red,
    onError = Color.White
)
MaterialTheme(
colors = if(isSystemInDarkTheme()) darkThemeColors else lightThemeColors
) {
    Column {
        Text(
        textStyle = TextStyle(color = MaterialTheme.colors.primary)
        )
    }
}

如果您想为主题添加更多自定义颜色,可以使用ColorPalette和扩展变量,如下所示:

@Composable
val ColorPalette.myColor: Color
    get() = if(!isLight) Color(0xFF424242) else Color.White

现在你可以使用MaterialTheme.colors.myColor来包含颜色。
如果您想要从Android颜色XML中包含颜色,可以使用colorResource(id = R.color.anyName)函数。

1
我在当前稳定的Compose Material版本1.0.3中没有找到ColorPalette。您必须在上述解决方案中使用Colors代替ColorPalette。当然,不需要使用@Composable注释。 - Shamsul Arafin Mahtab

3
你可以尝试这个方法:
inline fun <T> Resources.Theme.getAttribute(
    @AttrRes attr: Int,
    block: (TypedArray) -> T,
): T {
    val a = obtainStyledAttributes(intArrayOf(attr))
    return block(a).also { a.recycle() }
}

fun Resources.Theme.getDrawableAttribute(@AttrRes attr: Int): Drawable =
    getAttribute(attr) { it.getDrawable(0)!! }

fun Resources.Theme.getDimensionAttribute(@AttrRes attr: Int, defaultValue: Float = 0f): Float =
    getAttribute(attr) { it.getDimension(0, defaultValue) }

fun Resources.Theme.getStringAttribute(@AttrRes attr: Int): String? =
    getAttribute(attr) { it.getString(0) }

fun Resources.Theme.getColorAttribute(@AttrRes attr: Int, defaultValue: Int = 0): Int =
    getAttribute(attr) { it.getColor(0, defaultValue) }


@Composable
fun getDimensionAttribute(@AttrRes attr: Int, defaultValue: Float = 0f): Float =
    LocalContext.current.theme.getDimensionAttribute(attr, defaultValue)

@Composable
fun getStringAttribute(@AttrRes attr: Int): String? =
    LocalContext.current.theme.getStringAttribute(attr)

@Composable
fun getColorAttribute(@AttrRes attr: Int, defaultValue: Int = 0): Int =
    LocalContext.current.theme.getColorAttribute(attr, defaultValue)


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community
好的解决方案,但对我来说现在不起作用。它对你仍然有效吗? - knapweed1

2
如果您正在使用Material3,您将使用MaterialTheme.colorScheme:
Text(text = "Example",
     style = TextStyle(color = MaterialTheme.colorScheme.primary))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接