--- id: android-material3-you-theming title: Material 3 — Dynamic Color / Theme / Type category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [android, material, compose, theming, vibe-coding] tech_stack: { language: "Kotlin / Compose", applicable_to: ["Android"] } applied_in: [] aliases: [Material 3, Material You, dynamic color, MaterialTheme, color scheme] --- # Material 3 / Material You > Android 12+ wallpaper 색상 자동 (dynamic color). **MaterialTheme 안에서 Compose 컴포넌트가 자동**. Custom theme = 색 / type / shape 3축. 다크모드 지원. ## 📖 핵심 개념 - ColorScheme: Material 3 의 30+ 색 토큰 (primary / secondary / surface...). - Dynamic color: 시스템 wallpaper 에서 추출 (Android 12+). - Typography: 13 단계. - Shape: small / medium / large. ## 💻 코드 패턴 ### Material 3 setup ```kotlin @Composable fun AcmeTheme( darkTheme: Boolean = isSystemInDarkTheme(), dynamicColor: Boolean = true, content: @Composable () -> Unit, ) { val colorScheme = when { dynamicColor && Build.VERSION.SDK_INT >= 31 -> { val ctx = LocalContext.current if (darkTheme) dynamicDarkColorScheme(ctx) else dynamicLightColorScheme(ctx) } darkTheme -> DarkColors else -> LightColors } MaterialTheme( colorScheme = colorScheme, typography = AcmeTypography, shapes = AcmeShapes, content = content, ) } ``` ### 색 정의 ```kotlin private val LightColors = lightColorScheme( primary = Color(0xFF6750A4), onPrimary = Color.White, primaryContainer = Color(0xFFEADDFF), onPrimaryContainer = Color(0xFF21005D), secondary = Color(0xFF625B71), surface = Color(0xFFFFFBFE), onSurface = Color(0xFF1C1B1F), surfaceVariant = Color(0xFFE7E0EC), onSurfaceVariant = Color(0xFF49454F), error = Color(0xFFB3261E), background = Color(0xFFFFFBFE), ) private val DarkColors = darkColorScheme(...) ``` ### Theme builder 추천 - Material Theme Builder (web): 색 1개 입력 → 모든 token 자동. - Color tokens 코드 export. ### Typography ```kotlin val AcmeTypography = Typography( displayLarge = TextStyle(fontSize = 57.sp, lineHeight = 64.sp, letterSpacing = (-0.25).sp), headlineLarge = TextStyle(fontSize = 32.sp, lineHeight = 40.sp), titleLarge = TextStyle(fontSize = 22.sp, lineHeight = 28.sp), bodyLarge = TextStyle(fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.5.sp), labelLarge = TextStyle(fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.1.sp, fontWeight = FontWeight.Medium), ) ``` ```kotlin Text("Hello", style = MaterialTheme.typography.headlineLarge) ``` ### Shape ```kotlin val AcmeShapes = Shapes( small = RoundedCornerShape(4.dp), medium = RoundedCornerShape(8.dp), large = RoundedCornerShape(16.dp), ) ``` ### 컴포넌트 사용 ```kotlin Button(onClick = ...) { Text("Save") } FilledTonalButton(...) OutlinedButton(...) TextButton(...) Card { ... } ElevatedCard { ... } OutlinedCard { ... } NavigationBar { NavigationBarItem(...) } // 하단 NavigationRail { ... } // 옆 (큰 화면) NavigationDrawer { ... } ``` ### Top app bar (Material 3) ```kotlin @OptIn(ExperimentalMaterial3Api::class) @Composable fun MyScreen() { val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() Scaffold( topBar = { CenterAlignedTopAppBar( title = { Text("Acme") }, scrollBehavior = scrollBehavior, colors = TopAppBarDefaults.centerAlignedTopAppBarColors( scrolledContainerColor = MaterialTheme.colorScheme.surface, ), ) }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), ) { padding -> // ... } } ``` ### Dark mode 따라가기 ```kotlin @Composable fun MyApp() { AcmeTheme(darkTheme = isSystemInDarkTheme()) { // ... } } ``` ```kotlin // 강제 (사용자 설정) AcmeTheme(darkTheme = userPreference == "dark") ``` ### Edge-to-edge ```kotlin override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() super.onCreate(savedInstanceState) setContent { AcmeTheme { Scaffold { padding -> ... } } } } ``` ### Status bar / navigation bar 색 ```kotlin val view = LocalView.current SideEffect { val window = (view.context as Activity).window WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme } ``` ## 🤔 의사결정 기준 | 상황 | 추천 | |---|---| | 일반 앱 | Material 3 + dynamic color | | Brand 강 일관성 | dynamic color off + 자체 색 | | Cross-platform 디자인 | 자체 토큰 (Tailwind-like) | | 게임 / 강 visual | 자체 — Material 적은 사용 | | 쇼핑 / 컨텐츠 | Material 3 + brand color | ## ❌ 안티패턴 - **Color 직접 hard-code**: theme 안 써짐. token 사용. - **Dark mode 무시**: 사용자 시스템 따라가야. - **`Color.Black` / `Color.White` 매번**: contrast 깨짐. onSurface 등 token. - **Theme 밖 컴포넌트**: 무 styling. - **Typography 무시 — Text style 매번 직접**: 일관성 깨짐. - **Edge-to-edge 안 함 + 새 device**: 검은 bar 생김. - **시스템 status bar 색 같음**: 보임 어려움. controller. ## 🤖 LLM 활용 힌트 - Theme Builder 로 시작. - ColorScheme + Typography + Shape 3종. - enableEdgeToEdge + Scaffold. ## 🔗 관련 문서 - [[Android_Compose_State_Hoisting]] - [[Frontend_Design_Tokens]] - [[Frontend_Tailwind_Architecture]]