androidandroid-jetpack-composematerial-components-android

Jetpack Compose add custom dark/light colors?


Wh can create dark and light color palette, it's ok. enter image description here

But it has only 12 colors. How to add more custom colors for the light and dark palette?


Solution

  • You can use CompositionLocalProvider for that.

    1. Create a data class that will contain what you want to use and its staticCompositionLocalOf. For example CustomColorsPalette.kt:
    @Immutable
    data class CustomColorsPalette(
        val custom1OnBackground: Color = Color.Unspecified,
        val custom2OnBackground: Color = Color.Unspecified,
        val custom1OnSurface: Color = Color.Unspecified,
        val custom2OnSurface: Color = Color.Unspecified,
        val other1: Color = Color.Unspecified,
        val other2: Color = Color.Unspecified
    )
    
    val LocalCustomColorsPalette = staticCompositionLocalOf { CustomColorsPalette() }
    
    1. Create different variations, based on light or dark theme:
    val OnLightCustomColorsPalette = CustomColorsPalette(
        custom1OnBackground = Color(color = 0xFF1A237E),
        custom2OnBackground = Color(color = 0xFF1B5E20),
        custom1OnSurface = Color(color = 0xFFE53935),
        custom2OnSurface = Color(color = 0xFFD81B60),
        other1 = Color(color = 0xFF006064),
        other2 = Color(color = 0xFF643700)
    )
    
    val OnDarkCustomColorsPalette = CustomColorsPalette(
        custom1OnBackground = Color(color = 0xFF1E88E5),
        custom2OnBackground = Color(color = 0xFF43A047),
        custom1OnSurface = Color(color = 0xFFC62828),
        custom2OnSurface = Color(color = 0xFFAD1457),
        other1 = Color(color = 0xFF00897B),
        other2 = Color(color = 0xFF896200)
    )
    
    1. Use the logic in the Compose theme to decide when to use one or the other:
    @Composable
    fun AppTheme(
        darkTheme: Boolean = isSystemInDarkTheme(),
        content: @Composable () -> Unit
    ) {
        val colors = if (darkTheme) DarkColorPalette else LightColorPalette
        
        val customColorsPalette =
            if (darkTheme) OnDarkCustomColorsPalette
            else OnLightCustomColorsPalette
    
        CompositionLocalProvider(
            LocalCustomColorsPalette provides customColorsPalette
        ) {
            MaterialTheme(
                colors = colors,
                typography = Typography,
                shapes = Shapes,
                content = content
            )
        }
    }
    

    It is now possible to use these colors directly from the composable code with with LocalCustomColorsPalette.current:

    Text(
        text = "Anything...",
        color = LocalCustomColorsPalette.current.custom1OnBackground
    )
    

    More information about CompositionLocalProvider on docs.


    Bonus

    It is possible to change the call to LocalCustomColorsPalette.current to make it similar to what we have with the other properties of MaterialTheme. To do this, you can add the following code (it could be in the same file as the first step):

    // ...
    
    val MaterialTheme.customColorsPalette: CustomColorsPalette
        @Composable
        @ReadOnlyComposable
        get() = LocalCustomColorsPalette.current
    

    And now you can use like this:

    Text(
        text = "Anything...",
        color = MaterialTheme.customColorsPalette.custom1OnBackground
    )