Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Design Android app UI/UX following Material Design 3 guidelines with Jetpack Compose layout patterns.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/material3-theming.md
1# Material Design 3 Theming23## Color System45### Dynamic Color (Material You)67```kotlin8@Composable9fun AppTheme(10darkTheme: Boolean = isSystemInDarkTheme(),11dynamicColor: Boolean = true,12content: @Composable () -> Unit13) {14val colorScheme = when {15dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {16val context = LocalContext.current17if (darkTheme) dynamicDarkColorScheme(context)18else dynamicLightColorScheme(context)19}20darkTheme -> DarkColorScheme21else -> LightColorScheme22}2324MaterialTheme(25colorScheme = colorScheme,26typography = AppTypography,27shapes = AppShapes,28content = content29)30}31```3233### Custom Color Scheme3435```kotlin36// Define color palette37val md_theme_light_primary = Color(0xFF6750A4)38val md_theme_light_onPrimary = Color(0xFFFFFFFF)39val md_theme_light_primaryContainer = Color(0xFFEADDFF)40val md_theme_light_onPrimaryContainer = Color(0xFF21005D)41val md_theme_light_secondary = Color(0xFF625B71)42val md_theme_light_onSecondary = Color(0xFFFFFFFF)43val md_theme_light_secondaryContainer = Color(0xFFE8DEF8)44val md_theme_light_onSecondaryContainer = Color(0xFF1D192B)45val md_theme_light_tertiary = Color(0xFF7D5260)46val md_theme_light_onTertiary = Color(0xFFFFFFFF)47val md_theme_light_tertiaryContainer = Color(0xFFFFD8E4)48val md_theme_light_onTertiaryContainer = Color(0xFF31111D)49val md_theme_light_error = Color(0xFFB3261E)50val md_theme_light_onError = Color(0xFFFFFFFF)51val md_theme_light_errorContainer = Color(0xFFF9DEDC)52val md_theme_light_onErrorContainer = Color(0xFF410E0B)53val md_theme_light_background = Color(0xFFFFFBFE)54val md_theme_light_onBackground = Color(0xFF1C1B1F)55val md_theme_light_surface = Color(0xFFFFFBFE)56val md_theme_light_onSurface = Color(0xFF1C1B1F)57val md_theme_light_surfaceVariant = Color(0xFFE7E0EC)58val md_theme_light_onSurfaceVariant = Color(0xFF49454F)59val md_theme_light_outline = Color(0xFF79747E)60val md_theme_light_outlineVariant = Color(0xFFCAC4D0)6162val LightColorScheme = lightColorScheme(63primary = md_theme_light_primary,64onPrimary = md_theme_light_onPrimary,65primaryContainer = md_theme_light_primaryContainer,66onPrimaryContainer = md_theme_light_onPrimaryContainer,67secondary = md_theme_light_secondary,68onSecondary = md_theme_light_onSecondary,69secondaryContainer = md_theme_light_secondaryContainer,70onSecondaryContainer = md_theme_light_onSecondaryContainer,71tertiary = md_theme_light_tertiary,72onTertiary = md_theme_light_onTertiary,73tertiaryContainer = md_theme_light_tertiaryContainer,74onTertiaryContainer = md_theme_light_onTertiaryContainer,75error = md_theme_light_error,76onError = md_theme_light_onError,77errorContainer = md_theme_light_errorContainer,78onErrorContainer = md_theme_light_onErrorContainer,79background = md_theme_light_background,80onBackground = md_theme_light_onBackground,81surface = md_theme_light_surface,82onSurface = md_theme_light_onSurface,83surfaceVariant = md_theme_light_surfaceVariant,84onSurfaceVariant = md_theme_light_onSurfaceVariant,85outline = md_theme_light_outline,86outlineVariant = md_theme_light_outlineVariant87)8889// Dark colors follow the same pattern90val DarkColorScheme = darkColorScheme(91primary = md_theme_dark_primary,92// ... other colors93)94```9596### Color Roles Usage9798```kotlin99@Composable100fun ColorRolesExample() {101Column(102modifier = Modifier.padding(16.dp),103verticalArrangement = Arrangement.spacedBy(16.dp)104) {105// Primary - Key actions, FABs106Button(onClick = { }) {107Text("Primary Action")108}109110// Primary Container - Less prominent containers111Surface(112color = MaterialTheme.colorScheme.primaryContainer,113shape = RoundedCornerShape(12.dp)114) {115Text(116"Primary Container",117modifier = Modifier.padding(16.dp),118color = MaterialTheme.colorScheme.onPrimaryContainer119)120}121122// Secondary - Less prominent actions123FilledTonalButton(onClick = { }) {124Text("Secondary Action")125}126127// Tertiary - Contrast accents128Badge(129containerColor = MaterialTheme.colorScheme.tertiaryContainer,130contentColor = MaterialTheme.colorScheme.onTertiaryContainer131) {132Text("New")133}134135// Error - Destructive actions136Button(137onClick = { },138colors = ButtonDefaults.buttonColors(139containerColor = MaterialTheme.colorScheme.error140)141) {142Text("Delete")143}144145// Surface variants146Surface(147color = MaterialTheme.colorScheme.surfaceVariant,148shape = RoundedCornerShape(8.dp)149) {150Text(151"Surface Variant",152modifier = Modifier.padding(16.dp),153color = MaterialTheme.colorScheme.onSurfaceVariant154)155}156}157}158```159160### Extended Colors161162```kotlin163// Custom semantic colors beyond M3 defaults164data class ExtendedColors(165val success: Color,166val onSuccess: Color,167val successContainer: Color,168val onSuccessContainer: Color,169val warning: Color,170val onWarning: Color,171val warningContainer: Color,172val onWarningContainer: Color173)174175val LocalExtendedColors = staticCompositionLocalOf {176ExtendedColors(177success = Color(0xFF4CAF50),178onSuccess = Color.White,179successContainer = Color(0xFFE8F5E9),180onSuccessContainer = Color(0xFF1B5E20),181warning = Color(0xFFFF9800),182onWarning = Color.White,183warningContainer = Color(0xFFFFF3E0),184onWarningContainer = Color(0xFFE65100)185)186}187188@Composable189fun AppTheme(190content: @Composable () -> Unit191) {192val extendedColors = ExtendedColors(193// ... define colors based on light/dark theme194)195196CompositionLocalProvider(197LocalExtendedColors provides extendedColors198) {199MaterialTheme(200colorScheme = colorScheme,201content = content202)203}204}205206// Usage207@Composable208fun SuccessBanner() {209val extendedColors = LocalExtendedColors.current210211Surface(212color = extendedColors.successContainer,213shape = RoundedCornerShape(8.dp)214) {215Row(216modifier = Modifier.padding(16.dp),217horizontalArrangement = Arrangement.spacedBy(12.dp)218) {219Icon(220Icons.Default.CheckCircle,221contentDescription = null,222tint = extendedColors.success223)224Text(225"Operation successful!",226color = extendedColors.onSuccessContainer227)228}229}230}231```232233## Typography234235### Material 3 Type Scale236237```kotlin238val AppTypography = Typography(239// Display styles - Hero text, large numerals240displayLarge = TextStyle(241fontFamily = FontFamily.Default,242fontWeight = FontWeight.Normal,243fontSize = 57.sp,244lineHeight = 64.sp,245letterSpacing = (-0.25).sp246),247displayMedium = TextStyle(248fontFamily = FontFamily.Default,249fontWeight = FontWeight.Normal,250fontSize = 45.sp,251lineHeight = 52.sp,252letterSpacing = 0.sp253),254displaySmall = TextStyle(255fontFamily = FontFamily.Default,256fontWeight = FontWeight.Normal,257fontSize = 36.sp,258lineHeight = 44.sp,259letterSpacing = 0.sp260),261262// Headline styles - High emphasis, short text263headlineLarge = TextStyle(264fontFamily = FontFamily.Default,265fontWeight = FontWeight.Normal,266fontSize = 32.sp,267lineHeight = 40.sp,268letterSpacing = 0.sp269),270headlineMedium = TextStyle(271fontFamily = FontFamily.Default,272fontWeight = FontWeight.Normal,273fontSize = 28.sp,274lineHeight = 36.sp,275letterSpacing = 0.sp276),277headlineSmall = TextStyle(278fontFamily = FontFamily.Default,279fontWeight = FontWeight.Normal,280fontSize = 24.sp,281lineHeight = 32.sp,282letterSpacing = 0.sp283),284285// Title styles - Medium emphasis headers286titleLarge = TextStyle(287fontFamily = FontFamily.Default,288fontWeight = FontWeight.Normal,289fontSize = 22.sp,290lineHeight = 28.sp,291letterSpacing = 0.sp292),293titleMedium = TextStyle(294fontFamily = FontFamily.Default,295fontWeight = FontWeight.Medium,296fontSize = 16.sp,297lineHeight = 24.sp,298letterSpacing = 0.15.sp299),300titleSmall = TextStyle(301fontFamily = FontFamily.Default,302fontWeight = FontWeight.Medium,303fontSize = 14.sp,304lineHeight = 20.sp,305letterSpacing = 0.1.sp306),307308// Body styles - Long-form text309bodyLarge = TextStyle(310fontFamily = FontFamily.Default,311fontWeight = FontWeight.Normal,312fontSize = 16.sp,313lineHeight = 24.sp,314letterSpacing = 0.5.sp315),316bodyMedium = TextStyle(317fontFamily = FontFamily.Default,318fontWeight = FontWeight.Normal,319fontSize = 14.sp,320lineHeight = 20.sp,321letterSpacing = 0.25.sp322),323bodySmall = TextStyle(324fontFamily = FontFamily.Default,325fontWeight = FontWeight.Normal,326fontSize = 12.sp,327lineHeight = 16.sp,328letterSpacing = 0.4.sp329),330331// Label styles - Buttons, chips, navigation332labelLarge = TextStyle(333fontFamily = FontFamily.Default,334fontWeight = FontWeight.Medium,335fontSize = 14.sp,336lineHeight = 20.sp,337letterSpacing = 0.1.sp338),339labelMedium = TextStyle(340fontFamily = FontFamily.Default,341fontWeight = FontWeight.Medium,342fontSize = 12.sp,343lineHeight = 16.sp,344letterSpacing = 0.5.sp345),346labelSmall = TextStyle(347fontFamily = FontFamily.Default,348fontWeight = FontWeight.Medium,349fontSize = 11.sp,350lineHeight = 16.sp,351letterSpacing = 0.5.sp352)353)354```355356### Custom Fonts357358```kotlin359// Load custom fonts360val Inter = FontFamily(361Font(R.font.inter_regular, FontWeight.Normal),362Font(R.font.inter_medium, FontWeight.Medium),363Font(R.font.inter_semibold, FontWeight.SemiBold),364Font(R.font.inter_bold, FontWeight.Bold)365)366367val AppTypography = Typography(368displayLarge = TextStyle(369fontFamily = Inter,370fontWeight = FontWeight.Normal,371fontSize = 57.sp,372lineHeight = 64.sp373),374// Apply to all styles...375)376377// Variable fonts (Android 12+)378val InterVariable = FontFamily(379Font(380R.font.inter_variable,381variationSettings = FontVariation.Settings(382FontVariation.weight(400)383)384)385)386```387388## Shape System389390### Material 3 Shapes391392```kotlin393val AppShapes = Shapes(394// Extra small - Chips, small buttons395extraSmall = RoundedCornerShape(4.dp),396397// Small - Text fields, small cards398small = RoundedCornerShape(8.dp),399400// Medium - Cards, dialogs401medium = RoundedCornerShape(12.dp),402403// Large - Large cards, bottom sheets404large = RoundedCornerShape(16.dp),405406// Extra large - Full-screen dialogs407extraLarge = RoundedCornerShape(28.dp)408)409```410411### Custom Shape Usage412413```kotlin414@Composable415fun ShapedComponents() {416Column(417verticalArrangement = Arrangement.spacedBy(16.dp)418) {419// Small shape for text field420OutlinedTextField(421value = "",422onValueChange = {},423shape = MaterialTheme.shapes.small,424label = { Text("Input") }425)426427// Medium shape for cards428Card(429shape = MaterialTheme.shapes.medium430) {431Text("Card content", modifier = Modifier.padding(16.dp))432}433434// Large shape for prominent containers435Surface(436shape = MaterialTheme.shapes.large,437color = MaterialTheme.colorScheme.primaryContainer438) {439Text("Featured", modifier = Modifier.padding(24.dp))440}441442// Custom asymmetric shape443Surface(444shape = RoundedCornerShape(445topStart = 24.dp,446topEnd = 24.dp,447bottomStart = 0.dp,448bottomEnd = 0.dp449),450color = MaterialTheme.colorScheme.surface451) {452Text("Bottom sheet style", modifier = Modifier.padding(16.dp))453}454}455}456```457458## Elevation and Shadows459460### Tonal Elevation461462```kotlin463@Composable464fun ElevationExample() {465Column(466verticalArrangement = Arrangement.spacedBy(16.dp)467) {468// Level 0 - No elevation469Surface(470tonalElevation = 0.dp,471shadowElevation = 0.dp472) {473Text("Level 0", modifier = Modifier.padding(16.dp))474}475476// Level 1 - Low emphasis surfaces477Surface(478tonalElevation = 1.dp,479shadowElevation = 1.dp480) {481Text("Level 1", modifier = Modifier.padding(16.dp))482}483484// Level 2 - Cards, switches485Surface(486tonalElevation = 3.dp,487shadowElevation = 2.dp488) {489Text("Level 2", modifier = Modifier.padding(16.dp))490}491492// Level 3 - Navigation components493Surface(494tonalElevation = 6.dp,495shadowElevation = 4.dp496) {497Text("Level 3", modifier = Modifier.padding(16.dp))498}499500// Level 4 - Navigation rail501Surface(502tonalElevation = 8.dp,503shadowElevation = 6.dp504) {505Text("Level 4", modifier = Modifier.padding(16.dp))506}507508// Level 5 - FAB509Surface(510tonalElevation = 12.dp,511shadowElevation = 8.dp512) {513Text("Level 5", modifier = Modifier.padding(16.dp))514}515}516}517```518519## Responsive Design520521### Window Size Classes522523```kotlin524@Composable525fun AdaptiveLayout() {526val windowSizeClass = calculateWindowSizeClass(LocalContext.current as Activity)527528when (windowSizeClass.widthSizeClass) {529WindowWidthSizeClass.Compact -> {530// Phone portrait - Single column, bottom nav531CompactLayout()532}533WindowWidthSizeClass.Medium -> {534// Tablet portrait, phone landscape - Navigation rail535MediumLayout()536}537WindowWidthSizeClass.Expanded -> {538// Tablet landscape, desktop - Navigation drawer, multi-pane539ExpandedLayout()540}541}542}543544@Composable545fun CompactLayout() {546Scaffold(547bottomBar = { NavigationBar { /* items */ } }548) { padding ->549Content(modifier = Modifier.padding(padding))550}551}552553@Composable554fun MediumLayout() {555Row {556NavigationRail { /* items */ }557Content(modifier = Modifier.weight(1f))558}559}560561@Composable562fun ExpandedLayout() {563PermanentNavigationDrawer(564drawerContent = {565PermanentDrawerSheet { /* items */ }566}567) {568Row {569ListPane(modifier = Modifier.weight(0.4f))570DetailPane(modifier = Modifier.weight(0.6f))571}572}573}574```575576### Foldable Support577578```kotlin579@Composable580fun FoldableAwareLayout() {581val foldingFeature = LocalFoldingFeature.current582583when {584foldingFeature?.state == FoldingFeature.State.HALF_OPENED -> {585// Device is half-folded (tabletop mode)586TwoHingeLayout(587top = { CameraPreview() },588bottom = { CameraControls() }589)590}591foldingFeature?.orientation == FoldingFeature.Orientation.VERTICAL -> {592// Vertical fold (book mode)593TwoPaneLayout(594first = { NavigationPane() },595second = { ContentPane() }596)597}598else -> {599// Regular or fully opened600SinglePaneLayout()601}602}603}604```605