MaterialTheme Customization: A Comprehensive Guide in Jetpack Compose

Jetpack Compose, Android’s modern UI toolkit, leverages the power of MaterialTheme to provide a consistent and customizable design system. Customizing the MaterialTheme allows you to tailor the appearance of your application to match your brand and design requirements. This post will guide you through the various aspects of MaterialTheme customization in Jetpack Compose.

Understanding MaterialTheme in Jetpack Compose

MaterialTheme is a composable that encapsulates the design system for your application. It defines the color palette, typography, and shapes that are used throughout your UI. By customizing these properties, you can achieve a unique look and feel while maintaining consistency.

Why Customize MaterialTheme?

  • Brand Consistency: Ensures your application aligns with your brand’s visual identity.
  • Enhanced User Experience: Tailors the UI to match your target audience’s preferences.
  • Design Flexibility: Allows you to create a unique and visually appealing design.

How to Customize MaterialTheme

To customize MaterialTheme, you need to modify the Colors, Typography, and Shapes properties. Here’s how you can do it:

Step 1: Define Custom Colors

First, create a custom color palette. You can define primary, secondary, background, surface, and other colors that fit your design.

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)

val CustomPrimary = Color(0xFF123456)
val CustomSecondary = Color(0xFF654321)

Step 2: Create a Custom Color Scheme

Create a custom ColorScheme using the lightColorScheme or darkColorScheme functions:

import androidx.compose.material3.ColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme

val CustomLightColorScheme: ColorScheme = lightColorScheme(
    primary = CustomPrimary,
    secondary = CustomSecondary,
    tertiary = Pink40
)

val CustomDarkColorScheme: ColorScheme = darkColorScheme(
    primary = CustomPrimary,
    secondary = CustomSecondary,
    tertiary = Pink80
)

Step 3: Define Custom Typography

Create a custom typography by defining different text styles for headings, body text, captions, and more.

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
import androidx.compose.material3.Typography

val CustomTypography = Typography(
    bodyLarge = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp
    ),
    titleLarge = TextStyle(
        fontFamily = FontFamily.Serif,
        fontWeight = FontWeight.Bold,
        fontSize = 22.sp
    )
)

Step 4: Define Custom Shapes

Create custom shapes for components like buttons, cards, and dialogs by defining different corner radii.

import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp

val CustomShapes = Shapes(
    small = RoundedCornerShape(4.dp),
    medium = RoundedCornerShape(8.dp),
    large = RoundedCornerShape(16.dp)
)

Step 5: Apply the Custom MaterialTheme

Wrap your composable content with the MaterialTheme composable, passing in your custom ColorScheme, Typography, and Shapes:

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

@Composable
fun CustomThemeExample(content: @Composable () -> Unit) {
    MaterialTheme(
        colorScheme = CustomLightColorScheme,
        typography = CustomTypography,
        shapes = CustomShapes,
        content = content
    )
}

Example Usage

Here’s how you can use the custom MaterialTheme in your application:

import androidx.compose.material3.Text
import androidx.compose.material3.Button
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MyCustomUI() {
    Button(onClick = { /* Do something */ }) {
        Text(text = "Click Me", modifier = Modifier.padding(8.dp))
    }
}

@Preview(showBackground = true)
@Composable
fun PreviewMyCustomUI() {
    CustomThemeExample {
        MyCustomUI()
    }
}

Handling Dark Mode

To support dark mode, you can provide both a light and a dark color scheme and switch between them based on the system’s theme setting.

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme

@Composable
fun AppTheme(
    useDarkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable() () -> Unit
) {
    val context = LocalContext.current
    val colorScheme = when {
        useDarkTheme -> dynamicDarkColorScheme(context)
        else -> dynamicLightColorScheme(context)
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = CustomTypography,
        shapes = CustomShapes,
        content = content
    )
}

@Composable
@Preview(showBackground = true)
fun ThemedPreview() {
    AppTheme {
        MyCustomUI()
    }
}

Dynamic Color

MaterialTheme in Jetpack Compose supports dynamic color, allowing your app to adapt its color scheme based on the user’s wallpaper and system settings. To enable dynamic color, you can use dynamicLightColorScheme and dynamicDarkColorScheme.


import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext

@Composable
fun AppTheme(useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
    val context = LocalContext.current
    val colorScheme = if (useDarkTheme) {
        dynamicDarkColorScheme(context)
    } else {
        dynamicLightColorScheme(context)
    }

    MaterialTheme(colorScheme = colorScheme, content = content)
}

Conclusion

Customizing MaterialTheme in Jetpack Compose allows you to create a visually consistent and branded user interface. By defining custom colors, typography, and shapes, you can tailor the appearance of your application to meet your specific design requirements. Proper utilization of MaterialTheme enhances the user experience and ensures that your application stands out.