Jetpack Compose "onSurface" Color not working - android

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? 🤔
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))
}

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

Theming JetPack compose with background image

I am trying to theme jetpack compose background but using 2 images. The constraint I do have is that the background of few of my views are based on an image with another image on top. The second image on top is just a png mask playing with transparency.
I was wondering if I can do it by just using
#Composable
fun MyTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: #Composable () -> Unit
) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}
private val DarkColorPalette = darkColors(
primary = Purple200,
primaryVariant = Purple700,
secondary = Teal200
)
private val LightColorPalette = lightColors(
primary = Purple500,
primaryVariant = Purple700,
secondary = Teal200
/* Other default colors to override
background = Color.White,
surface = Color.White,
onPrimary = Color.White,
onSecondary = Color.Black,
onBackground = Color.Black,
onSurface = Color.Black,
*/
)
I would like to see if I can use the background params to inject images or I will have to do it in each view by just adding images which are using full screen mode

Compose - Custom MaterialTheme colors not working?

I want to custom colors system using Compose, but it isn't working. It effected by colors in themes.xml.
Activity
class DemoComposeMainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val colorPrimary = colorResource(R.color.md_green_500)
val colorSecondary = colorResource(R.color.md_orange_500)
val colors = lightColors(
primary = colorPrimary,
primaryVariant = colorPrimary,
onPrimary = Color.White,
secondary = colorSecondary,
secondaryVariant = colorSecondary,
onSecondary = Color.White)
MaterialTheme(colors = colors) {
// TODO
}
}
}
}
Please help me. Thanks.
The statusbar color is based on the android:statusBarColor defined in your app theme.
If you want to change the statusBar color you can use the accompanist library.
Something like.
val systemUiController = rememberSystemUiController()
val useDarkIcons = MaterialTheme.colors.isLight
SideEffect {
systemUiController.setSystemBarsColor(
color = Color.Transparent,
darkIcons = useDarkIcons
)
// setStatusBarsColor() and setNavigationBarsColor() also exist
}

IllegalStateException: CompositionLocal LocalConfiguration not present Android

I'm trying to use staticCompositionLocalOf in Jetpack Compose according to this article on Medium.
This is my ProvidableCompositionLocal
val lightColors = lightColors(
primary = LightColor.BackgroundWhite,
primaryVariant = LightColor.ToolbarWhite,
secondary = LightColor.FabBlue,
secondaryVariant = LightColor.BackgroundWhite,
surface = LightColor.SurfaceWhite,
onPrimary = LightColor.TextBlack,
onSecondary = LightColor.TextBlack,
onSurface = LightColor.TextBlack
)
val darkColors = darkColors(
primary = DarkColor.BackgroundBlue,
primaryVariant = DarkColor.ToolbarBlue,
secondary = DarkColor.FabGrey,
secondaryVariant = DarkColor.BackgroundBlue,
surface = DarkColor.SurfaceBlue,
onPrimary = Color.White,
onSecondary = Color.White,
onSurface = Color.White
)
private val DarkColorPalette =
Colors(
material = darkColors,
toolbar = DarkColor.ToolbarBlue,
background = DarkColor.BackgroundBlue,
surface = DarkColor.SurfaceBlue,
fab = DarkColor.FabGrey,
pink = DarkColor.Pink
)
private val LightColorPalette =
Colors(
material = lightColors,
toolbar = LightColor.ToolbarWhite,
background = LightColor.BackgroundWhite,
surface = LightColor.SurfaceWhite,
fab = LightColor.FabBlue,
pink = LightColor.Pink
)
val TheColor: Colors
#Composable
#ReadOnlyComposable
get() = LocalColors.current
}
val LocalColors = staticCompositionLocalOf { DarkColorPalette }
This is the wrapper around the normal Colors class provided by Compose class. The material variable is the normal Colors class.
data class Colors(
val material: Colors,
val toolbar: Color,
val background: Color,
val surface: Color,
val fab: Color,
val pink: Color
) {
val primary: Color get() = material.primary
val primaryVariant: Color get() = material.primaryVariant
val secondary: Color get() = material.secondary
val secondaryVariant: Color get() = material.secondaryVariant
// val background: Color get() = material.background
// val surface: Color get() = material.surface
val error: Color get() = material.error
val onPrimary: Color get() = material.onPrimary
val onSecondary: Color get() = material.onSecondary
val onBackground: Color get() = material.onBackground
val onSurface: Color get() = material.onSurface
val onError: Color get() = material.onError
val isLight: Boolean get() = material.isLight
}
I have also provided it in my Theme function as shown below. I'm getting the darkTheme from Android DataStore
#Composable
fun BMICalculatorTheme(
darkTheme: Boolean,
content: #Composable () -> Unit
) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
CompositionLocalProvider(LocalColors provides colors) {
MaterialTheme(
colors = colors.material,
typography = CabinTypography,
shapes = Shapes,
content = content
)
}
}
However, I'm getting the below error but can't find any online resources that can help me fix it. In case any further information is needed, I would be more than happy to clarify. Any help would be highly appreciated.
IllegalStateException: CompositionLocal LocalConfiguration not present
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.noLocalProvidedFor(AndroidCompositionLocals.android.kt:123)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.access$noLocalProvidedFor(AndroidCompositionLocals.android.kt:1)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$LocalConfiguration$1.invoke(AndroidCompositionLocals.android.kt:44)
at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$LocalConfiguration$1.invoke(AndroidCompositionLocals.android.kt:43)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at androidx.compose.runtime.LazyValueHolder.getCurrent(ValueHolders.kt:29)
at androidx.compose.runtime.LazyValueHolder.getValue(ValueHolders.kt:31)
at androidx.compose.runtime.ComposerImpl.resolveCompositionLocal(Composer.kt:1895)
at androidx.compose.runtime.ComposerImpl.consume(Composer.kt:1865)
at androidx.compose.foundation.DarkTheme_androidKt.isSystemInDarkTheme(DarkTheme.android.kt:52)
at com.octagon_technologies.bmicalculator.data.ThemeDataStore$isDarkMode$$inlined$map$1$2.emit(Collect.kt:135)
at kotlinx.coroutines.flow.FlowKt__ErrorsKt$catchImpl$$inlined$collect$1.emit(Collect.kt:134)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke(SafeCollector.kt:15)
at kotlinx.coroutines.flow.internal.SafeCollectorKt$emitFun$1.invoke(Unknown Source:4)
at kotlinx.coroutines.flow.internal.SafeCollector.emit(SafeCollector.kt:77)
at kotlinx.coroutines.flow.internal.SafeCollector.emit(SafeCollector.kt:59)
at androidx.datastore.core.SingleProcessDataStore$data$1$invokeSuspend$$inlined$map$1$2.emit(Collect.kt:139)
at kotlinx.coroutines.flow.FlowKt__LimitKt$dropWhile$$inlined$unsafeFlow$1$lambda$1.emit(Collect.kt:137)
at kotlinx.coroutines.flow.StateFlowImpl.collect(StateFlow.kt:348)
at kotlinx.coroutines.flow.StateFlowImpl$collect$1.invokeSuspend(Unknown Source:12)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
The problem appears to be here:
... ThemeDataStore$isDarkMode$$inlined$map$1$2.emit(Collect.kt:135)
From the stack trace it looks like the isSystemInDarkTheme is being called inside a lambda passed to collect() which, since it is an #Composable function, it should only be called from another #Composable function and cannot be called inside a flow collect().
The compiler should have reported this an error. Please consider reporting this as a compose compiler plugin bug.

Material Theme Colors results in blank Jetpack Compose Button

A simple composable with default Material Theme colors (code below) results in the following preview image (both in IDE and on device)
#Preview
#Composable
fun PreviewCalendar() {
MaterialTheme {
Column{
Row{Text("Hello World")}
Row{Button(onClick = {}){Text("Hello World Button")} }
}
}
}
When providing my own colors, then the button becomes blank (code and screenshot below). Reading through source for Button I would have expected the button to have primary as the background color. Have I implemented my colors incorrectly? I could not find a bug report for similar behavior
val lightTheme =
Colors(
primary = Color(0x0d47a1),
primaryVariant = Color(0x5472d3),
secondary = Color(0x212121),
secondaryVariant = Color(0x484848),
background = Color(0xffffff),
surface = Color(0xffffff),
error = Color(0xB00020),
onPrimary = Color(0xffffff),
onSecondary = Color(0xffffff),
onBackground = Color(0x000000),
onSurface = Color(0x000000),
onError = Color(0xffffff),
isLight = true
)
#Preview
#Composable
fun PreviewCalendar() {
MaterialTheme(colors = lightTheme) {
Column{
Row{Text("Hello World")}
Row{Button(onClick = {}){Text("Hello World Button")} }
}
}
}
I generated these colors using google's material theme tools, but did not notice that Compose was looking for ARGB color space. All the colors that I specified had an alpha value of 0, and were therefore transparent. The correct colors are:
val lightTheme =
Colors(
primary = Color(0xFF0d47a1),
primaryVariant = Color(0xFF5472d3),
secondary = Color(0xFF212121),
secondaryVariant = Color(0xFF484848),
background = Color(0xFFffffff),
surface = Color(0xFFffffff),
error = Color(0xFFB00020),
onPrimary = Color(0xFFffffff),
onSecondary = Color(0xFFffffff),
onBackground = Color(0xFF000000),
onSurface = Color(0xFF000000),
onError = Color(0xFFffffff),
isLight = true
)

How do I use Color resource directly in Jetpack Compose?

I want to use custom colors defined in the colors.xml class directly without using the Material theme colors or the default theme provided by the Jetpack. Is there any straightforward way to do it?
You can use colorResource() which loads a color resource.
Text(
text = "Hello World",
color = colorResource(R.color.purple_200)
)
To use color in jetpack compose using recommended create a package ui.theme in com.<domain_name>.<app_name> which will likely be present by default if you are creating empty compose project. Now create Color.kt and Theme.kt kotlin files if they are not present in your project.
In Color.kt add the colors you need
package com.<domain_name>.<app_name>.ui.theme
import androidx.compose.ui.graphics.Color
val Purple200 = Color(0xFFBB86FC)
val Purple500 = Color(0xFF6200EE)
val Purple700 = Color(0xFF3700B3)
val Teal200 = Color(0xFF03DAC5)
val Flower = Color(0xFF4CAF50)
val Deer = Color(0xFFFF5722)
val Mango = Color(0xFFFF9800)
val AppbarColor = Color(0xFF2196F3)
Here is ready to use a Material Color template made by me
There are 3 common ways of using colors
Method 1 : Directly use color
import com.<domain_name>.<app_name>.ui.theme.*
Text(text = "Hello ", color = Flower)
Method 2 : Override default MaterialTheme colors
Now in, Theme.kt
private val DarkColorPalette = darkColors(
primary = Purple200,
primaryVariant = Purple700,
secondary = Teal200,
onBackground = Flower //Custom color
)
private val LightColorPalette = lightColors(
primary = Purple500,
primaryVariant = Purple700,
secondary = Teal200,
onBackground = Deer //Custom color
/* Other default colors to override
background = Color.White,
surface = Color.White,
onPrimary = Color.White,
onSecondary = Color.Black,
onBackground = Color.Black,
onSurface = Color.Black,
*/
)
#Composable
fun NotepadTheme(darkTheme: Boolean = isSystemInDarkTheme(),
content:#Composable() () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = Typography,
shapes = Shapes,
content = content
)
}
MainActivity.kt
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ColorApp()
}
}
}
#Composable
fun ColorApp() {
ColorTheme {
Surface(modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background) {
Greeting("Android")
}
}
}
#Composable
fun Greeting(name: String) {
Text(text = "Hello $name!", color = MaterialTheme.colors.onBackground) //Using color
}
#Preview(
showBackground = true, name = "Light mode",
uiMode = Configuration.UI_MODE_NIGHT_NO or
Configuration.UI_MODE_TYPE_NORMAL
)
#Preview(
showBackground = true, name = "Night mode",
uiMode = Configuration.UI_MODE_NIGHT_YES or
Configuration.UI_MODE_TYPE_NORMAL
)
#Composable
fun DefaultPreview() {
ColorApp()
}
Method 3 : Custom theme (Recommended method)
Text(text = "Hello ", color = AppNameTheme.colors.customColor)

Categories

Resources