Jetpack Compose "onSurface" Color not working

Viewed 2578

I'm testing with Material Theming with Jetpack Compose and I'm not sure why I can't make the theme's onSurface color work.

Here is the Theme.kt with a onSurface color set to Color.Red:

private val DarkColorPalette = darkColors(
    primary = Purple200,
    primaryVariant = Purple700,
    secondary = Teal200,
    onSurface = Color.Red, // <------- HERE
    onPrimary = Color.Blue, // <----- HERE
)

private val LightColorPalette = lightColors(
    primary = Purple500,
    primaryVariant = Purple700,
    secondary = Teal200,
    onSurface = Color.Red, // <------- AND HERE
    onPrimary = Color.Blue, // <----- HERE
)

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

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

and here is the Activity:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApp()
        }
    }
}

@Preview
@Composable
fun MyApp() {
    ExploringMaterialTheme {
        // I also tried
        // Surface(color = MaterialTheme.colors.surface) {
        Surface {
            Text(text = "Hello!!", modifier = Modifier.padding(16.dp))
        }
    }
}

I was expecting "Hello!!" to be shown in Red, but instead, it's shown in normal black. Any ideas what I'm missing?

result

It works has expected when I set the a color in Surface component. Surface gets the right on Color (the onPrimary in this case):

        Surface(color = MaterialTheme.colors.primary) {
            Text(text = "Hello!!", modifier = Modifier.padding(16.dp))
        }

result2

2 Answers

The Surface composable uses:

CompositionLocalProvider(
        LocalContentColor provides contentColor){
            //
            content()
}

where the contentColor is defined by:

fun Colors.contentColorFor(backgroundColor: Color): Color {
    return when (backgroundColor) {
    primary -> onPrimary
    primaryVariant -> onPrimary
    secondary -> onSecondary
    secondaryVariant -> onSecondary
    background -> onBackground
    surface -> onSurface
    error -> onError
    else -> Color.Unspecified
    }
}

Currently you have to specify the surface color in your theme:

private val LightColorPalette = lightColors(
    primary = Blue500,
    surface = Color.Yellow)

In this case the Text uses the onSurface color.

If you don't specify the surface color the Surface components use the background as colorBackground and the onBackground for the Text.

There seems to be some issue where the color matches the background color instead of the surface color, so it returns the onBackground. If you set your surface color so that it is different from the background color then it will pick the correct onSurface color, for insance

private val DarkColorPalette = darkColors(
    primary = Purple200,
    primaryVariant = Purple700,
    secondary = Teal200,
    onSurface = Color.Red,
    surface = Color.Green,
)

This may be a bug in compose.

This happens here:

fun Colors.contentColorFor(backgroundColor: Color): Color {
    return when (backgroundColor) {
    primary -> onPrimary
    primaryVariant -> onPrimary
    secondary -> onSecondary
    secondaryVariant -> onSecondary
    background -> onBackground
    surface -> onSurface
    error -> onError
    else -> Color.Unspecified
    }
}
Related