Skip to content

Latest commit

 

History

History
174 lines (137 loc) · 4.55 KB

08-theming-material3.md

File metadata and controls

174 lines (137 loc) · 4.55 KB

Theming with Material 3

MaterialTheme

MaterialTheme wraps your app and provides colors, typography, and shapes. Every Material 3 composable reads these values automatically.

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

@Composable
fun MyApp(content: @Composable () -> Unit) {
    TaskManagerTheme {
        Surface { content() }
    }
}

Surface applies the theme's background color. Text picks up the theme's on-surface color without extra config.

Color Schemes

Define a lightColorScheme and a darkColorScheme. Each sets roles like primary, background, and surface.

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

private val LightColors = lightColorScheme(
    primary = Color(0xFF6650A4),
    onPrimary = Color.White,
    secondary = Color(0xFF625B71),
    background = Color(0xFFFFFBFE),
    surface = Color(0xFFFFFBFE),
)

private val DarkColors = darkColorScheme(
    primary = Color(0xFFD0BCFF),
    onPrimary = Color(0xFF381E72),
    secondary = Color(0xFFCCC2DC),
    background = Color(0xFF1C1B1F),
    surface = Color(0xFF1C1B1F),
)

Pick Theme Based on System

Read the system dark mode with isSystemInDarkTheme() and choose the scheme:

import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable

@Composable
fun TaskManagerTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colors = if (darkTheme) DarkColors else LightColors
    MaterialTheme(
        colorScheme = colors,
        content = content
    )
}

Now your app follows the user's system setting automatically.

Dynamic Color (Android 12+)

On Android 12 and later, dynamic color derives the palette from the user's wallpaper. Use dynamicLightColorScheme and dynamicDarkColorScheme:

import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.dynamicDarkColorScheme

@Composable
fun TaskManagerTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    dynamicColor: Boolean = true,
    content: @Composable () -> Unit
) {
    val context = LocalContext.current
    val colors = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            if (darkTheme) dynamicDarkColorScheme(context)
            else dynamicLightColorScheme(context)
        }
        darkTheme -> DarkColors
        else -> LightColors
    }
    MaterialTheme(colorScheme = colors, content = content)
}

Typography

Define text styles in a Typography object:

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

val AppTypography = Typography(
    titleLarge = TextStyle(
        fontSize = 22.sp,
        fontWeight = FontWeight.Bold
    ),
    bodyLarge = TextStyle(
        fontSize = 16.sp,
        fontWeight = FontWeight.Normal
    )
)

// Usage
MaterialTheme(
    colorScheme = colors,
    typography = AppTypography,
    content = content
)

Then use the styles by role:

Text("My Tasks", style = MaterialTheme.typography.titleLarge)
Text("5 pending", style = MaterialTheme.typography.bodyLarge)

Shapes

Control corner roundness with Shapes:

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

val AppShapes = Shapes(
    small = RoundedCornerShape(8.dp),
    medium = RoundedCornerShape(16.dp),
    large = RoundedCornerShape(24.dp)
)

MaterialTheme(shapes = AppShapes, content = content)

Card, Button, and TextField now use these corner radii.

Access Theme Values

Read any theme value with MaterialTheme.colorScheme, MaterialTheme.typography, or MaterialTheme.shapes:

Box(
    modifier = Modifier
        .background(MaterialTheme.colorScheme.surfaceVariant)
        .padding(16.dp)
) {
    Text("Themed", color = MaterialTheme.colorScheme.onSurfaceVariant)
}

Practice Exercise

Create a custom theme with a teal primary color, a titleLarge style of 28sp bold, and medium shape of 20dp corners. Apply it to a Card containing a title and a body text. Toggle the system dark mode and confirm both themes look correct.