Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

Compose의 테마 설정

Jetpack Compose를 사용하면 테마를 적용하여 앱에 일관된 디자인과 분위기를 쉽게 제공할 수 있습니다. Compose의 머티리얼 디자인 구현을 제품 브랜드에 맞게 맞춤설정할 수 있습니다. 요구사항에 맞지 않으면 Compose의 공개 API를 사용하여 맞춤 디자인 시스템을 빌드할 수 있습니다.

애플리케이션 전체 테마 설정

Jetpack Compose는 디지털 인터페이스를 만들기 위한 포괄적인 디자인 시스템인 머티리얼 디자인 구현을 제공합니다. 머티리얼 디자인 구성요소(버튼, 카드, 스위치 등)는 제품 브랜드를 효과적으로 반영하기 위해 머티리얼 디자인을 맞춤설정하는 체계적인 방법인 머티리얼 테마 설정을 기반으로 빌드됩니다. 머티리얼 테마는 색상, 서체도형 속성으로 구성됩니다. 이러한 속성을 맞춤설정하면 앱을 빌드하는 데 사용되는 구성요소에 변경사항이 자동으로 반영됩니다.

Jetpack Compose는 MaterialTheme 컴포저블을 사용하여 다음 개념을 구현합니다.

MaterialTheme(
  colors = …,
  typography = …,
  shapes = …
) {
  // app content
}

MaterialTheme에 전달하는 매개변수를 구성하여 애플리케이션의 테마를 설정합니다.

두 개의 대조되는 스크린샷. 첫 번째는 기본 MaterialTheme 스타일 지정을 사용하고 두 번째 스크린샷은 수정된 스타일 지정을 사용합니다.

그림 1. 첫 번째 스크린샷은 MaterialTheme을 구성하지 않는 앱을 보여주며 기본 스타일 지정을 사용합니다. 두 번째 스크린샷은 MaterialTheme에 매개변수를 전달하여 스타일 지정을 맞춤설정하는 앱을 보여줍니다.

색상

색상은 Compose에서 간단한 데이터 보유 클래스인 Color 클래스로 모델링됩니다.

val red = Color(0xffff0000)
val blue = Color(red = 0f, green  0f, blue = 1f)

원하는 대로 색상을 구성할 수 있지만(예: 싱글톤 내에서 또는 정의된 인라인으로 최상위 상수로 구성) 테마에 색상을 지정하고 거기에서 색상을 검색하는 것이 좋습니다. 이 접근 방식을 사용하면 어두운 테마와 같은 여러 테마를 지원할 수 있습니다.

테마 색상 팔레트의 예

Compose는 Colors 클래스를 제공하여 머티리얼 색상 시스템을 모델링합니다. Colors는 다음과 같이 밝거나 어두운 색상 세트를 만드는 빌더 함수를 제공합니다.

private val yellow200 = Color(0xffffeb46)
private val blue200 = Color(0xff91a4fc)
…

private val DarkColors = darkColors(
  primary = yellow200,
  secondary = blue200,
  …
)
private val LightColors = lightColors(
  primary = yellow500,
  primaryVariant = yellow400,
  secondary = blue700,
  …
)

Colors를 정의한 후에는 MaterialTheme에 전달할 수 있습니다.

MaterialTheme(
  colors = if (darkTheme) DarkColors else LightColors,
  typography = …,
  shapes = …
) {
  // app content
}

테마 색상 사용

MaterialTheme.colors를 사용하여 MaterialTheme 컴포저블에 제공된 Colors를 검색할 수 있습니다.

Text(
  text = "Hello theming",
  color = MaterialTheme.colors.primary
)

표시 경로 및 콘텐츠 색상

많은 구성요소가 한 쌍의 색상 및 '콘텐츠 색상'을 허용합니다.

Surface(
  color: Color = MaterialTheme.colors.surface,
  contentColor: Color = contentColorFor(color),
  …

TopAppBar(
  backgroundColor: Color = MaterialTheme.colors.primarySurface,
  contentColor: Color = contentColorFor(backgroundColor),
…

이를 통해 컴포저블의 색상을 설정할 수 있을 뿐만 아니라 그 안에 포함된 컴포저블인 콘텐츠의 기본 색상을 제공할 수도 있습니다. 많은 컴포저블은 기본적으로 이 콘텐츠 색상을 사용합니다. 예를 들어 Text는 상위 요소의 콘텐츠 색상을 기반으로 색상을 설정하고 Icon은 이 색상을 사용하여 색조를 설정합니다.

색상이 다른 동일한 배너의 두 가지 예

그림 2. 배경 색상을 다르게 설정하면 서로 다른 텍스트 및 아이콘 색상이 생성됩니다.

contentColorFor() 메서드는 테마 색상에 적절한 '설정' 색상을 검색합니다. 예를 들어 primary 배경을 설정하면 onPrimary가 콘텐츠 색상으로 설정됩니다. 테마가 아닌 배경 색상을 설정하는 경우 적절한 콘텐츠 색상도 지정해야 합니다. AmbientContentColor를 사용하여 현재 배경과 대조되는 현재 콘텐츠 색상을 검색합니다.

콘텐츠 알파

콘텐츠를 강조하는 정도를 달리하여 중요도를 전달하고 시각적 계층 구조를 알려야 할 때가 많습니다. 머티리얼 디자인에서는 다양한 수준의 불투명도를 사용하여 다양한 중요도 수준을 전달하도록 권장합니다.

Jetpack Compose에서는 AmbientContentAlpha를 사용해 이를 구현합니다. amaient 값을 제공하여 계층 구조의 콘텐츠 알파를 지정할 수 있습니다. 하위 컴포저블에서 이 값을 사용합니다. 예를 들어 TextIcon은 기본적으로 AmbientContentAlpha를 사용하도록 조정된 AmbientContentColor 조합을 사용합니다. 머티리얼에서는 ContentAlpha 객체에 의해 모델링된 일부 표준 알파 값(high, medium, disabled)을 지정합니다. MaterialTheme의 기본값은 AmbientContentAlpha~ContentAlpha.high입니다.

// By default, both Icon & Text use the combination of AmbientContentColor &
// AmbientContentAlpha. De-emphasize content by setting content alpha
Providers(AmbientContentAlpha provides ContentAlpha.medium) {
    Text(…)
}
Providers(AmbientContentAlpha provides ContentAlpha.disabled) {
    Icon(…)
    Text(…)
}

다양한 텍스트 강조 수준을 보여주는 기사 제목의 스크린샷

그림 3. 텍스트에 다양한 수준의 강조를 적용하여 정보 계층 구조를 시각적으로 전달할 수 있습니다.

어두운 테마

Compose에서 MaterialTheme 컴포저블에 다양한 Colors 세트를 제공하고 테마를 통해 색상을 사용하여 밝은 테마 및 어두운 테마를 구현합니다.

@Composable
fun MyTheme(
  darkTheme: Boolean = isSystemInDarkTheme(),
  content: @Composable () -> Unit
) {
  MaterialTheme(
    colors = if (darkTheme) DarkColors else LightColors,
    typography = …,
    shapes = …,
    content = content
  )
}

이 예에서 MaterialTheme은 어두운 테마를 사용할지 여부를 지정하는 매개변수를 받는 자체의 구성 가능한 함수로 래핑되어 있습니다. 이 경우 함수는 기기 테마 설정을 쿼리하여 darkTheme의 기본값을 가져옵니다.

어두운 테마를 구현할 때 다음과 같이 현재 Colors가 밝은지 또는 어두운지 확인할 수 있습니다.

val isLightTheme = MaterialTheme.colors.isLight

이 값은 lightColors()darkColors() 빌더 함수에 의해 설정됩니다.

머티리얼에서 고도가 높은 어두운 테마의 표시 경로는 배경을 밝게 하는 고도 오버레이를 수신합니다. 이러한 오버레이는 어두운 색상을 사용할 때 Surface 컴포저블에 의해 자동으로 구현됩니다.

Surface(
  elevation = 2.dp,
  color = MaterialTheme.colors.surface, // color will adjusted for elevation
  …

고도 수준이 다양한 요소에 사용되는 미묘하게 다른 색상을 보여주는 앱의 스크린샷

그림 4. 카드 및 하단 탐색은 배경과 같이 surface 색상이 지정되어 있지만 더 높은 고도에 있기 때문에 색상이 약간 더 밝습니다.

머티리얼 색상 확장

Compose는 머티리얼의 색상 테마 설정을 면밀하게 모델링하므로 간단하고 유형이 안전한 방식으로 머티리얼 가이드라인을 따를 수 있습니다. 색상 세트를 확장해야 한다면 아래와 같이 자체 색상 시스템을 구현하거나 확장을 추가할 수 있습니다.

@Composable
val Colors.snackbarAction: Color
  get() = if (isLight) Red300 else Red700

서체

머티리얼은 유형 시스템을 정의하여 의미론적으로 이름이 지정된 소수의 스타일을 사용하도록 권장합니다.

다양한 스타일의 여러 가지 다른 서체의 예

Compose는 Typography, TextStyle글꼴 관련 클래스를 사용하여 유형 시스템을 구현합니다. Typography 생성자는 각 스타일의 기본값을 제공하므로 맞춤설정하지 않으려는 스타일은 생략할 수 있습니다.

private val Rubik = fontFamily(
    font(R.font.rubik_regular),
    font(R.font.rubik_medium, FontWeight.W500),
    font(R.font.rubik_bold, FontWeight.Bold)
)

private val MyTypography = Typography(
  h1 = TextStyle(
    fontFamily = Rubik,
    fontWeight = FontWeight.W300,
    fontSize = 96.sp
  ),
  body1 = TextStyle(
    fontFamily = Rubik,
    fontWeight = FontWeight.W600,
    fontSize = 16.sp
  )
  …
)
MaterialTheme(typography = MyTypography, …)

전체적으로 동일한 글꼴을 사용하려면 다음과 같이 defaultFontFamily 매개변수를 지정하고 TextStyle 요소의 fontFamily를 생략합니다.

val typography = Typography(defaultFontFamily = Rubik)
MaterialTheme(typography = typography, …)

텍스트 스타일 사용

다음 예와 같이 테마에서 TextStyle을 검색합니다.

Text(
    text = "Subtitle2 styled"
    style = MaterialTheme.typography.subtitle2
)

다양한 용도의 다양한 서체가 혼합된 것을 보여주는 스크린샷

그림 5. 다양한 서체와 스타일을 사용하여 브랜드를 표현할 수 있습니다.

도형

머티리얼은 도형 시스템을 정의합니다. 이 시스템을 통해 대형, 중형 및 소형 구성요소의 도형을 정의할 수 있습니다.

다양한 머티리얼 디자인 도형을 보여주는 예

Compose는 Shapes 클래스를 통해 도형 시스템을 구현합니다. 이 클래스를 사용하면 각 카테고리의 CornerBasedShape를 지정할 수 있습니다.

val Shapes = Shapes(
  small = RoundedCornerShape(percent = 50),
  medium = RoundedCornerShape(0f),
  large = CutCornerShape(
    topLeft = 16.dp,
    topRight = 0.dp,
    bottomRight = 0.dp,
    bottomLeft = 16.dp
  )
)

MaterialTheme(shapes = Shapes, …)

많은 구성요소가 기본적으로 이러한 도형을 사용합니다. 예를 들어 Button, TextFieldFloatingActionButton은 기본적으로 소형으로, AlertDialog는 기본적으로 중형으로, ModalDrawerLayout은 기본적으로 대형으로 설정됩니다. 전체 매핑은 도형 구성표 참조를 참고하세요.

도형 사용

다음과 같이 테마에서 도형을 검색합니다.

Surface(
  shape = MaterialTheme.shapes.medium …
) {
  ...
}

머티리얼 도형을 사용하여 요소의 상태를 전달하는 앱의 스크린샷

그림 6. 도형을 사용하여 브랜드 또는 상태를 표현할 수 있습니다.

구성요소 스타일

Compose에는 구성요소 스타일에 대한 명시적인 개념이 없습니다. 자체 컴포저블을 생성하여 이 기능을 제공하기 때문입니다. 예를 들어 버튼 스타일을 만들려면 고유의 구성 가능한 함수로 버튼을 래핑하고 변경하려는 매개변수를 직접 설정하며 포함하는 컴포저블에 매개변수로 다른 매개변수를 노출합니다.

@Composable
fun LoginButton(
  onClick: () -> Unit,
  modifier: Modifier = Modifier,
  text: @Composable () -> Unit) {
  Button(
    backgroundColor = MaterialTheme.colors.secondary,
    onClick = onClick,
    modifier = modifier,
    text = text
  }
}

맞춤 디자인 시스템

머티리얼은 권장되는 디자인 시스템이며 Jetpack Compose는 머티리얼 구현을 제공하지만, 개발자는 사용에 제한받지 않습니다. 동일한 방식으로 자체 디자인 시스템을 만드는 것이 전적으로 가능합니다. 머티리얼은 이를 달성하는 데 사용할 수 있는 공개 API를 기반으로 완전히 빌드되었습니다.

맞춤 디자인 시스템을 빌드하는 방법은 이 문서에서 다루지 않습니다. 이에 관한 자세한 설명은 다음 리소스를 참조하세요.

자세히 알아보기

자세히 알아보려면 Jetpack Compose 테마 설정 Codelab을 참조하세요.