코딩

Material Design & 테마 커스터마이징

Eastpark 2025. 1. 5. 22:03
728x90
반응형

이번 글에서는 안드로이드 앱 전체 분위기를 좌우하는 Material Design 테마(Theme) 커스터마이징에 대해 살펴보려고 한다. Compose에서는 MaterialTheme와 다양한 Material 컴포넌트(Button, TextField, Card, etc.)를 손쉽게 활용할 수 있는데,

이를 통해 일관된 브랜드 아이덴티티 UX를 구현하는 방법을 알아보자.


1. Compose와 Material Design

1.1 Material Design이란?

Material Design은 구글에서 제안하는 디자인 시스템으로, 일관성 있는 UX와 UI를 구축하기 위해 색상, 타이포그래피, 레이아웃, 모션 등을 체계화한 개념이다.

Material 2 (고전적인 Material)과 Material 3 (Material You)가 존재하며, Compose는 최신 디자인 시스템인 Material 3도 지원한다.

1.2 Compose의 MaterialTheme

Jetpack Compose에서는 MaterialTheme 함수를 통해 전역 테마를 정의하고,

내부에 배치되는 모든 컴포넌트에 스타일이 자동 적용되도록 할 수 있다.

색상(Color), 폰트(Typography), 모양(Shape)을 지정해주면, 해당 테마가 Button, Text, Surface 등의 Material 컴포넌트에 반영된다.

@Composable
fun MyAppTheme(content: @Composable () -> Unit) {
    MaterialTheme(
        colors = lightColors(
            primary = Color(0xFF6200EE),
            primaryVariant = Color(0xFF3700B3),
            secondary = Color(0xFF03DAC6),
        ),
        typography = Typography(),
        shapes = Shapes(),
        content = content
    )
}

lightColors()는 라이트 모드에 필요한 색상 팔레트를 제공한다.

content는 실제 화면에 배치될 Composable 함수들을 감싸면서 테마가 적용되도록 한다.

참고

Material 3 버전을 사용할 때는 MaterialTheme.colorScheme, MaterialTheme.typography, MaterialTheme.shapes 식으로 접근한다.

Gradle 의존성에서 androidx.compose.material3:material3 라이브러리가 필요할 수 있다.


2. Light Mode & Dark Mode 전환

2.1 DayNight 테마와 Compose

안드로이드에는 기존부터 DayNight 테마(혹은 Dark Mode) 개념이 있었다. Compose에서도 이를 쉽게 구현할 수 있는데, isSystemInDarkTheme() 함수를 사용하면 시스템이 다크 모드인지 감지할 수 있다.

@Composable
fun MyDynamicTheme(content: @Composable () -> Unit) {
    val darkTheme = isSystemInDarkTheme()
    
    val colors = if (darkTheme) {
        darkColors(
            primary = Color(0xFFBB86FC),
            secondary = Color(0xFF03DAC6)
        )
    } else {
        lightColors(
            primary = Color(0xFF6200EE),
            secondary = Color(0xFF03DAC6)
        )
    }
    
    MaterialTheme(
        colors = colors,
        typography = Typography(),
        shapes = Shapes(),
        content = content
    )
}

시스템 전체가 다크 모드일 때 darkTheme true로 설정하고, 그에 맞는 색상 팔레트를 적용한다.

MaterialTheme에서 색상을 가져다 쓰는 컴포넌트들은 자동으로 라이트/다크 모드에 대응한다.

2.2 Dark Mode 전환 시 유의사항

대비(Contrast)를 충분히 확보해, 텍스트나 아이콘이 배경색에 묻히지 않도록 한다.

MaterialTheme에서 제공하는 “onPrimary”, “onSecondary”처럼 *on 계열 색상을 적절히 설정해 텍스트 가독성을 챙긴다.


3. Material 컴포넌트 살펴보기

MaterialTheme와 함께 자주 쓰이는 Compose Material 컴포넌트 몇 가지를 간단히 살펴보자.

3.1 Button & FloatingActionButton

@Composable
fun MyButtons() {
    Column {
        Button(onClick = { /*TODO*/ }) {
            Text("Material Button")
        }
        
        FloatingActionButton(onClick = { /*TODO*/ }) {
            Icon(Icons.Default.Add, contentDescription = "FAB Icon")
        }
    }
}

Button: 기본적인 Material 버튼

FloatingActionButton: 보통 화면 우측 하단에 띄워지는 동그란 버튼

3.2 TextField

@Composable
fun MyTextField(value: String, onValueChange: (String) -> Unit) {
    TextField(
        value = value,
        onValueChange = onValueChange,
        label = { Text("입력해주세요") }
    )
}

TextField: 사용자 입력을 받는 필드

라벨(label)이나 플레이스홀더(placeholder) 등 Material Design 표준 규격을 준수한다.

 

3.3 Card & Surface

@Composable
fun MyCard() {
    Card(
        elevation = 4.dp,
        shape = RoundedCornerShape(8.dp)
    ) {
        Text(text = "이곳은 Card 내부", modifier = Modifier.padding(16.dp))
    }
}

Card: Material 스타일의 카드 레이아웃

Surface는 배경색, 모양(Shape)을 세밀하게 지정하고 싶을 때 유용하다.


4. 예제: Light/Dark Mode 스위치

MaterialTheme를 직접 적용해보는 실습으로, Light/Dark Mode를 버튼 클릭으로 전환하는 예제를 만들어본다.

(실제 앱에서는 시스템 설정과 연동하거나, 사용자 설정을 저장해두는 방식을 사용할 수 있다.)

@Composable
fun ThemeToggleApp() {
    var darkTheme by remember { mutableStateOf(false) }
    
    val colors = if (darkTheme) {
        darkColors(primary = Color(0xFFBB86FC))
    } else {
        lightColors(primary = Color(0xFF6200EE))
    }
    
    MaterialTheme(colors = colors) {
        Surface(modifier = Modifier.fillMaxSize()) {
            Column(
                modifier = Modifier.padding(16.dp),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    text = if (darkTheme) "다크 모드" else "라이트 모드",
                    style = MaterialTheme.typography.h4
                )
                Spacer(modifier = Modifier.height(16.dp))
                
                Button(onClick = { darkTheme = !darkTheme }) {
                    Text("모드 전환")
                }
            }
        }
    }
}

1. darkTheme 변수를 remember mutableStateOf로 선언한다.

2. darkTheme true darkColors(), false lightColors()를 생성한다.

3. MaterialTheme 안에 Surface, Column, Text, Button을 배치해 UI를 구성한다.

4. 버튼을 클릭할 때마다 darkTheme가 토글되면서, 라이트/다크 모드가 전환된다.


5. 마무리

이번에는 Material Design을 Compose에서 어떻게 활용하는지, 그

리고 테마(MaterialTheme)를 커스터마이징하는 방법을 살펴봤다.

핵심 포인트는 Light/Dark Mode 지원 일관된 색상/타이포그래피/Shape 설정에 있다.

MaterialTheme는 앱의 전체적인 디자인 가이드를 아우르는 매우 강력한 도구다.

Dark Mode 전환 시 isSystemInDarkTheme() 함수를 사용하거나, 수동으로 색상 팔레트를 적용할 수 있다.

Material 컴포넌트(Button, TextField, Card 등)를 테마와 함께 사용하면, 프로젝트 전반에 일관된 스타일이 깔리므로, 브랜드 이미지를 확고히 하기도 쉽다.

728x90
반응형