https://kotlinlang.org logo
Title
b

bbade_

12/15/2021, 12:20 AM
Question about MaterialTheme and overriding a color in a segment of code. If i had a layout
Column
  Button1
  *OddUi*
  Button3
Lets say i wanted to override
primary
and
onPrimary
when rendering the OddUi content. What’s the best way of doing this? MaterialTheme’s colors are
mutableStateOf
, so do i write
Button1()
MaterialTheme.primary = somethingElse
MaterialTheme.Colors.onPrimary = somethingElse
OddUi()
// restore the two colors
Button2
This feels odd or would i write
Button1()
CompositionLocalProvider(LocalColors provides MaterialTheme.colors.copy(primary = ..., onPrimary = ...) {
   OddUi()
}
Button2
With this though, localColors is internal, so i can’t override it, right? Is there a third option?
c

Chris Sinco [G]

12/15/2021, 1:32 AM
CompositionLocal is one way. What is happening in that code is that you are providing a different set of colors to LocalColors
The other alternative is you wrap OddUi in another MaterialTheme or YourAppTheme block and override:
MaterialTheme(
    colors = MaterialTheme.colors.copy(primary = ...)
) {
    OddUi()
}
If your overrides grow beyond two values, I may recommend creating a separate theme Composable that wraps MaterialTheme or YourAppTheme, then use that directly in the OddUi hierarchy
@Composable
fun OddUi() {
    OddUiTheme {
        ...
    }
}

@Composable
private fun OddUiTheme(
    content: @Composable () -> Unit
) {
    MaterialTheme(
        colors = ...,
        typography = ...,
        ...,
    ) {
        content()
    }
}
b

bbade_

12/15/2021, 2:06 AM
Got it, thanks!
Also, do you know what the intent is of having the properties of
Colors
be mutableStates? Rather than having the
Colors
class be immutable?
c

Chris Sinco [G]

12/15/2021, 2:14 AM
I didn’t design the API but my guess is that it’s to support switching colors on the fly based on app / system state, to then recompose hierarchies, e.g. switching between light/dark mode. @Louis Pullen-Freilich [G] could maybe provide more details.
l

Louis Pullen-Freilich [G]

12/15/2021, 2:18 AM
For this case you can just use another
MaterialTheme
with a different set of colors around the content as Chris mentioned.
MutableState
is used so that if you are animating / changing one color, only components that consume that color recompose, which makes it a lot more efficient to animate colors in a theme
:thank-you: 1
1
👏 1
r

Rick Regan

12/15/2021, 3:50 PM
I had been wondering why the colors were
MutableState
and in fact still am. In Material 3 terms, in ColorScheme.kt, functions
lightColorScheme
and
darkColorScheme
return a new
ColorScheme
. Under what conditions are the individual colors then changed within those `ColorScheme`s?
l

Louis Pullen-Freilich [G]

12/15/2021, 4:24 PM
Internally
MaterialTheme
uses the color schemes provided to update its internal color scheme, by changing each individual color https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]nMain/kotlin/androidx/compose/material3/MaterialTheme.kt;l=66
r

Rick Regan

12/15/2021, 4:30 PM
Thanks. I've added extended colors into my app, modeling my
ExtendedColorScheme
class on
ColorScheme
. I made my colors
mutableStateOf
as well with a TBD to understand why. Now I think that I don't need to make them mutable 🙂.
😒ame: 1
l

Louis Pullen-Freilich [G]

12/15/2021, 4:59 PM
If you have no plans to animate between different color schemes, or you don’t regularly change some values in your scheme (for example, changing just the primary color depending on some content on the screen like in a music player application) then yeah, there’s no need to make them mutable. It can just be a
CompositionLocal
 with a simple class of immutable colors