Home > Software engineering >  Strange behaviour on text color in jetpack compose
Strange behaviour on text color in jetpack compose

Time:07-19

Hey I am new in jetpack compose. I tried to set window background color black and white according to theme. When I created custom theme and set background color my text color will be black.

theme.kt

package com.vivek.sportsresult.ui.theme

import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import com.google.accompanist.systemuicontroller.rememberSystemUiController

private val DarkColorScheme = darkColorScheme(
    primary = Purple80,
    secondary = PurpleGrey80,
    tertiary = Pink80,
    background = Color.Black
)

private val LightColorScheme = lightColorScheme(
    primary = Purple40,
    secondary = PurpleGrey40,
    tertiary = Pink40,
    background = Color.White
)

@Composable
fun SportsResultTheme(
    darkTheme: Boolean = isDarkTheme(),
    // Dynamic color is available on Android 12 
    dynamicColor: Boolean = true,
    content: @Composable () -> Unit
) {
    val systemUiController = rememberSystemUiController()
    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
        }
    }

    if (darkTheme) {
        systemUiController.setSystemBarsColor(
            color = Color.Black
        )
    } else {
        systemUiController.setSystemBarsColor(
            color = Color.White
        )
    }

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

@Composable
fun isDarkTheme() = isSystemInDarkTheme()

@Composable
fun getBackgroundColor() = if (isDarkTheme()) {
    DarkColorScheme.background
} else {
    LightColorScheme.background
}

MainActivity.kt

package com.vivek.sportsresult

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import com.vivek.sportsresult.ui.theme.SportsResultTheme
import com.vivek.sportsresult.ui.theme.getBackgroundColor

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SportsResultTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = getBackgroundColor()
                ) {
                    Log.e("TAG", "onCreate: ")
                    Greeting("Android")
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    SportsResultTheme {
        Greeting("Android")
    }
}

When I tried to use color = getBackgroundColor() it not changing text color but if use color = MaterialTheme.colorScheme.background it working correct on dark and white theme. I don't understand why? Can someone guide me on this?

Actual Output

enter image description here

Expected Output

enter image description here

CodePudding user response:

When you use MaterialTheme.colorScheme.background it works correctly because in that case the Surface composable is able to determine the correct content color (that would be the contentColor parameter) based on the background color which you set (which is the color parameter).

However, when you use getBackgroundColor() in dark mode you get back Color.Black and since you are running your code on a device with Android 12 your theme is a dynamic color theme which was created here

    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

and apparently does not contain any color that is exactly Color.Black, i.e. that is exactly Color(0xFF000000), and thus the Surface composable is unable to determine the correct content color.

When a given color is not found in the theme then the contentColor is set to LocalContentColor.current and it just happens that in your case this results in a black text on a black background.

You have 2 options:

  1. you can use MaterialTheme.colorScheme.background and let it determine the contentColor automatically based on your theme.
  2. you can set both color and contentColor yourself like this
Surface(
    modifier = Modifier.fillMaxSize(),
    color = getBackgroundColor(),
    contentColor = /* get and set some content color */, 
)

This behavior is due to how Surface contentColor parameter default value is implemented by calling contentColorFor(color). See the Surface composable implementation and contentColorFor implementation (in Android Studio you Ctrl/Cmd click on them, or open the context menu > Go To > Implementation).

  • Related