Mastering Custom Theming with Material You in Jetpack Compose

Jetpack Compose has revolutionized Android UI development, making it easier and more intuitive to build stunning and responsive user interfaces. Material You, the latest evolution of Material Design, allows for even greater customization and personalization in theming. By leveraging Material You in Jetpack Compose, developers can create visually consistent and user-friendly apps that adapt seamlessly to the user’s device and preferences.

What is Material You?

Material You, introduced with Android 12, is a design paradigm that focuses on personalizing the user experience by dynamically adapting the color palette based on the user’s wallpaper. It aims to make applications feel more integrated with the user’s device and overall system theme.

Key Features of Material You

  • Dynamic Color: Extracts colors from the user’s wallpaper to create a harmonious and personalized theme.
  • Customization: Offers extensive customization options to tailor the theme to your app’s unique branding.
  • Accessibility: Provides enhanced accessibility features to ensure your app is usable by everyone.

Implementing Material You Theming in Jetpack Compose

To get started with Material You theming in Jetpack Compose, follow these steps:

Step 1: Add Dependencies

First, make sure you have the necessary dependencies in your build.gradle file:

dependencies {
    implementation("androidx.compose.material3:material3:1.1.2")
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.activity:activity-compose:1.8.2")
}

Step 2: Create a Theme

Define your app’s theme using the MaterialTheme composable, incorporating dynamic colors:


import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat

private val DarkColorScheme = darkColorScheme(
    // Define your dark theme colors here
)

private val LightColorScheme = lightColorScheme(
    // Define your light theme colors here
)

@Composable
fun MyAppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    dynamicColor: Boolean = true,
    content: @Composable () -> Unit
) {
    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
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            val window = (view.context as Activity).window
            window.statusBarColor = colorScheme.primary.toArgb()
            WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        content = content
    )
}

Key points in this theme definition:

  • Dynamic Color Scheme: Dynamically chooses color schemes based on device settings and user wallpaper if running on Android 12 (SDK 31) or higher.
  • Color Scheme Customization: Fallbacks to manually defined light and dark color schemes for older Android versions.
  • Status Bar Customization: Customizes the status bar color and appearance (light or dark) based on the selected theme.

Step 3: Use Custom Colors

Create a Color.kt file to define and manage custom colors within your app.


import androidx.compose.ui.graphics.Color

val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8BC)

val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)

Step 4: Implement the App

Integrate the theme into your main composable:


import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.example.myapplication.ui.theme.MyAppTheme

@Composable
fun AppContent() {
    Text("Hello Material You!")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    MyAppTheme {
        AppContent()
    }
}

Step 5: Adapt to Dark Mode

Material You supports both light and dark modes. Detect the system’s dark mode setting and apply the appropriate theme:


import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable

@Composable
fun MyApp(content: @Composable () -> Unit) {
    val isDarkMode = isSystemInDarkTheme()

    MaterialTheme {
        content()
    }
}

Advanced Customization

Material You provides further customization options to align your app’s theme with your brand identity.

1. Custom Color Palettes

Define your own custom color palettes using ColorScheme for light and dark modes:


import androidx.compose.ui.graphics.Color
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme

val MyLightColorScheme = lightColorScheme(
    primary = Color(0xFF6200EE),
    secondary = Color(0xFF03DAC5),
    tertiary = Color(0xFF3700B3),
    background = Color(0xFFFFFFFF),
    surface = Color(0xFFFFFFFF),
    onPrimary = Color(0xFFFFFFFF),
    onSecondary = Color(0xFF000000),
    onTertiary = Color(0xFFFFFFFF),
    onBackground = Color(0xFF000000),
    onSurface = Color(0xFF000000)
)

val MyDarkColorScheme = darkColorScheme(
    primary = Color(0xFFBB86FC),
    secondary = Color(0xFF03DAC6),
    tertiary = Color(0xFF3700B3),
    background = Color(0xFF121212),
    surface = Color(0xFF121212),
    onPrimary = Color(0xFF000000),
    onSecondary = Color(0xFF000000),
    onTertiary = Color(0xFF000000),
    onBackground = Color(0xFFFFFFFF),
    onSurface = Color(0xFFFFFFFF)
)

2. Shape and Typography Customization

Customize shapes and typography to match your brand guidelines:


import androidx.compose.material3.Shapes
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp

val MyShapes = Shapes(
    small = RoundedCornerShape(4.dp),
    medium = RoundedCornerShape(8.dp),
    large = RoundedCornerShape(0.dp)
)

val MyTypography = Typography(
    bodyLarge = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp
    )
)

Conclusion

Custom theming with Material You in Jetpack Compose provides a powerful and flexible way to create personalized and visually appealing Android applications. By leveraging dynamic colors, custom palettes, and advanced customization options, you can tailor your app’s theme to align seamlessly with the user’s device and preferences. Material You enables developers to build cohesive and user-friendly interfaces, enhancing the overall user experience.