Jetpack Compose is Android’s modern UI toolkit, designed to simplify and accelerate UI development. One of its standout features is its powerful theming capabilities. Theming allows you to define and apply a consistent visual style throughout your app, making it easier to maintain a cohesive look and feel. This blog post delves into theming in Jetpack Compose, explaining how to define custom themes, apply colors, typography, shapes, and more.
What is Theming in Jetpack Compose?
Theming in Jetpack Compose is a way to encapsulate visual design elements—like colors, typography, and shapes—into a single, reusable entity. By creating a custom theme, you ensure consistency and make it easier to update the look and feel of your application. It also promotes better code organization and maintainability.
Why Use Theming?
- Consistency: Ensures all UI components adhere to a unified visual style.
- Maintainability: Simplifies updating the app’s look and feel across the entire codebase.
- Reusability: Themes can be reused across different parts of the app, or even across multiple apps.
- Customization: Allows easy switching between light and dark themes, or other custom variants.
How to Implement Theming in Jetpack Compose
Theming in Compose involves defining your own Theme
composable that sets the overall look and feel for the components it wraps.
Step 1: Set Up Dependencies
Ensure that you have the necessary dependencies added in your build.gradle
file:
dependencies {
implementation("androidx.compose.ui:ui:1.6.1")
implementation("androidx.compose.material:material:1.6.1")
implementation("androidx.compose.ui:ui-tooling-preview:1.6.1")
debugImplementation("androidx.compose.ui:ui-tooling:1.6.1")
}
Step 2: Define Colors
Start by defining a set of colors that your theme will use. You can create a Color.kt
file:
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)
These color values can then be used in both light and dark theme color schemes.
Step 3: Create Color Schemes for Light and Dark Themes
Next, create color schemes for light and dark themes using the lightColorScheme
and darkColorScheme
APIs from androidx.compose.material3
:
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.ui.graphics.Color
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.Black,
onTertiary = Color.Black,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
Step 4: Define Typography
Define a custom typography using the Typography
class. Create a Typography.kt
file:
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
// Set of Material typography styles to start with
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp
)
*/
)
You can customize different text styles according to your app’s design specifications.
Step 5: Define Shapes
Define shapes for components like buttons, cards, etc., using the Shapes
class. Create a Shape.kt
file:
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp
val Shapes = Shapes(
small = RoundedCornerShape(4.dp),
medium = RoundedCornerShape(8.dp),
large = RoundedCornerShape(0.dp)
)
Define different shapes for small, medium, and large components, as needed.
Step 6: Create a Custom Theme Composable
Create a custom Theme
composable to encapsulate the color schemes, typography, and shapes. This will typically be in a file named Theme.kt
:
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
shapes = Shapes,
content = content
)
}
The MyAppTheme
composable encapsulates the theme settings and uses the MaterialTheme
to apply these settings.
Step 7: Apply the Theme in Your App
Wrap your composable content with the MyAppTheme
composable:
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.example.myapp.ui.theme.MyAppTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
// Your app content goes here
Greeting("Android")
}
}
}
}
@Composable
fun Greeting(name: String, modifier: androidx.compose.ui.Modifier = androidx.compose.ui.Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MyAppTheme {
Greeting("Android")
}
}
Now, all the composables within MyAppTheme
will use the specified colors, typography, and shapes.
Using Theme Attributes in Composables
You can access the current theme’s attributes in your composables using MaterialTheme
.
Accessing Colors
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
@Composable
fun ThemedText(text: String) {
Text(
text = text,
color = MaterialTheme.colorScheme.primary
)
}
This uses the primary color defined in the current theme.
Accessing Typography
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.TextStyle
@Composable
fun ThemedTitle(text: String) {
Text(
text = text,
style = MaterialTheme.typography.headlineLarge
)
}
This applies the headlineLarge
style defined in your custom typography.
Accessing Shapes
import androidx.compose.foundation.shape.CornerBasedShape
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun ThemedButton(text: String, onClick: () -> Unit) {
Button(
onClick = onClick,
shape = MaterialTheme.shapes.medium
) {
Text(text = text)
}
}
This applies the medium shape to the button.
Conclusion
Theming in Jetpack Compose allows you to create a consistent and visually appealing user interface across your Android application. By defining custom colors, typography, and shapes, you can easily maintain and update the look and feel of your app. Jetpack Compose’s theming capabilities help streamline UI development and improve code organization.