안드로이드 시스템·Compose 용어 사전
ComposecolorScheme · typography · 디자인 토큰

MaterialTheme

색·타이포·셰이프의 단일 출처. 역할 기반 색이 다크모드를 공짜로 만든다.

색 · 타이포 · 셰이프의 단일 출처.

MaterialTheme(
    colorScheme = if (isSystemInDarkTheme()) DarkColors else LightColors,
    typography = AppTypography,
    shapes = AppShapes
) { content() }

// 사용
Text("제목", style = MaterialTheme.typography.headlineMedium,
     color = MaterialTheme.colorScheme.onSurface)

색을 "역할"로 쓴다

❌ Color(0xFF1A1A1A) 를 직접 쓴다

  • 다크모드에서 검은 배경에 검은 글씨가 된다
  • 색을 바꾸려면 200곳을 찾아야 한다

✅ colorScheme.onSurface 를 쓴다

  • 라이트/다크 각각의 스킴이 알맞은 값을 준다
  • 다크모드가 공짜가 된다
짝을 이루는 규칙
  primary   ↔ onPrimary      (primary 배경 위의 내용 색)
  surface   ↔ onSurface
  error     ↔ onError

"on" 이 붙은 색은 그 배경 위에서 대비가 보장된다 — 접근성이 설계에 들어있다

동적 색상

val colors = when {
    Build.VERSION.SDK_INT >= 31 && dynamicColor ->
        if (dark) dynamicDarkColorScheme(ctx) else dynamicLightColorScheme(ctx)
    dark -> DarkColors
    else -> LightColors
}

Android 12+ 에서 사용자의 배경화면에서 뽑은 색을 쓴다

  • 시스템과 어우러진다

대가: 브랜드 색이 사라진다

  • 브랜드가 중요한 앱은 끄거나 일부만 적용한다

다크모드는 색만이 아니다

  • 이미지의 밝기 (어두운 배경에 흰 로고)
  • 그림자 대신 표면 톤 (다크에서는 elevation 이 색으로 표현된다)
  • 상태바/내비바 아이콘 색 (WindowInsetsControllerCompat)

isSystemInDarkTheme() 은 시스템 설정만 본다 앱 내 토글을 두려면 값을 DataStore 에 저장해 직접 관리한다

자체 디자인 시스템으로 확장

// Material 에 없는 토큰을 CompositionLocal 로 추가한다
val LocalSpacing = staticCompositionLocalOf { Spacing() }
data class Spacing(val small: Dp = 4.dp, val medium: Dp = 8.dp, val large: Dp = 16.dp)

CompositionLocalProvider(LocalSpacing provides Spacing()) { MaterialTheme { content() } }

면접 함정

  • "다크모드는 색 반전" → 대비·이미지·elevation 표현까지 함께 설계해야 한다.
  • "테마를 안 쓰고 상수 파일에 색을 모으면 같다" → 컴포지션 위치에 따라 다른 테마를 줄 수 없고, 미리보기에서 테마 전환도 안 된다.

미리보기에서 두 테마를 함께 본다

@Preview(name = "라이트")
@Preview(name = "다크", uiMode = Configuration.UI_MODE_NIGHT_YES)
annotation class ThemePreviews

@ThemePreviews
@Composable fun HomePreview() = AppTheme { HomeScreen(state = sampleState) }

elevation이 다크에서 색으로 표현된다

Material 3 에서 표면 톤(surface tone) 이 계층을 표현한다
  라이트  그림자로 떠 있음을 표현
  다크    그림자가 안 보이므로 표면을 더 밝게 해 표현

Surface(tonalElevation = 3.dp) 를 쓰면 두 모드에서 알아서 처리된다 색을 직접 지정하면 다크에서 계층이 평평해진다

시스템 바 색을 맞춘다

val view = LocalView.current
SideEffect {
    val window = (view.context as Activity).window
    WindowCompat.getInsetsController(window, view)
        .isAppearanceLightStatusBars = !darkTheme
}

안 맞추면 라이트 배경에 흰 상태바 아이콘이 겹쳐 안 보인다 (Android 15+ 는 edge-to-edge 가 기본이라 더 자주 마주친다)

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — Compose Material 3·테마 — 색·타이포·다크모드