본문 바로가기

안드로이드 Android

안드로이드 개발 (15) Theming in Compose

오늘도 Compose 내용 정리를 이어서 해보겠습니다.

Compose의 테마 설정

- Compose는 테마를 적용하여 앱에 일관된 디자인과 분위기를 쉽게 제공을 함

- 기본적으로 Compose의 머티리얼 디자인 구현을 만드려는 앱에 맞게 맞춤설정이 가능

- 머티리얼 디자인 뿐만 아니라 다른 Compose의 공개 API를 사용하여 맞춤 디자인 시스템을 만들 수 있음

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

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

머티리얼 디자인 구성요소(버튼, 카드, 스위치 등)는 나만의 앱을 효과적으로 반영하기 위해

머티리얼 디자인을 맞춤설정하는 체계적인 방법인 머티리얼 테마 설정을 기반으로 빌드됩니다.

 

- 머티리얼 테마는 색상, 서체  도형 속성으로 구성

- 속성을 맞춤설정하면 앱에 사용되는 구성요소에 변경사항이 자동 적용

 

1. 색상

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

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

- 원하는 대로 색상을 구성할 수 있음

  (ex: 싱글톤 내에서 또는 정의된 인라인으로 최상위 상수로 구성)

 

- 테마에 색상을 지정하고 거기에서 색상을 검색하는 것이 좋음

  (이 방식을 사용하면 여러 테마를 지원할 수 있습니다.)

Compose는 Colors 클래스를 제공하여 머티리얼 색상 시스템을 모델링합니다. 

https://material.io/design/color/the-color-system.html#color-usage-and-palettes

 

Material Design

Build beautiful, usable products faster. Material Design is an adaptable system—backed by open-source code—that helps teams build high quality digital experiences.

material.io

 

1) Colors는 다음과 같이 밝거나(light) 어두운(dark) 색상 세트를 만드는 함수를 제공

 

예제

    private val Yellow200 = Color(0xffffeb46)
    private val Yellow400 =  Color(0xFFFFEE58)
    private val Yellow500 = Color(0xFFFFEB3B)

    private val Blue200 = Color(0xff91a4fc)
    private val Blue700 = Color(0xFFBECAFF)


    private val DarkColors = darkColors(
        primary = Yellow200,
        secondary = Blue200,
    )
    private val LightColors = lightColors(
        primary = Yellow500,
        primaryVariant = Yellow400,
        secondary = Blue700,
    )
    @Composable
    private fun MyTheme(
    darkTheme: Boolean = isSystemInDarkTheme()
    ) {
        MaterialTheme(
            colors = if (darkTheme) DarkColors else LightColors
        ) {
            //머티리얼 테마가 적용되는 영역
        }
    }

- Colors를 정의한 후에는 MaterialTheme에 전달할 수 있음

 

 

실사용

 MaterialTheme(
            colors = if (darkTheme) DarkColors else LightColors
        ) {
            Text(
                text = "Hello theming",
                color = MaterialTheme.colors.primary
            )
        }

MaterialTheme.colors를 사용하면 MaterialTheme Composable에 제공된Colors를 검색할 수 있음

 

결과

 


2) 표시 경로 및 콘텐츠 색상

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

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

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

 

- contentColor를 통해 Composable의 색상 설정과 그 안에 포함된 Composable인 콘텐츠의 기본 색상을 제공할 수 있음.

-많은 Composable은 기본적으로 이 콘텐츠 색상을 사용합니다.

- contentColorFor() 메서드는 테마 색상에 적절한 '설정' 색상을 검색

  (예를 들어 primary 배경을 설정하면 onPrimary가 콘텐츠 색상으로 설정됩니다.)

 

 

 

예를 들어  Text는 상위 요소의 콘텐츠 색상을 기반으로 색상을 설정하고  Icon은 이 색상을 사용하여 색조를 설정합니다.

 

테마가 아닌 배경 색상을 설정하는 경우 적절한 콘텐츠 색상도 지정해야 합니다.

 LocalContentColor 를 사용하여 현재 배경과 대조되는 현재 콘텐츠 색상을 검색합니다.

 

참고: Surface가 적절한 콘텐츠 색상을 설정하기 때문에  Surface를 사용하여 색상을 설정하는 것을 권장

(적절한 콘텐츠 색상이 설정되지 않는 직접 Modifier.background() 호출에 주의할 것.)

 

 

3) 콘텐츠 알파

콘텐츠를 강조하는 정도를 조절해서 중요도를 표시할 때가 많습니다.

머티리얼 디자인에서는 불투명도를 사용하여 다양한 중요도 수준을 전달하도록 권장합니다.

이는 LocalContentAlpha를 사용하면 됩니다.

 

LocalContentAlpha

- CompositionLocal 값을 제공하여 계층 구조의 콘텐츠 알파를 지정할 수 있음

- 하위 Composable에서 이 값을 사용함

 

예제

@Composable
    private fun AlphaTest() {
        Column {
            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
                Text("test")
            }
            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
                Icon(painter = painterResource(id = R.drawable.ic_launcher_background), null)
                Text("asdasdasdasdas")
            }
        }
    }

- Text  Icon은 기본적으로 LocalContentAlpha를 사용하도록 조정된 LocalContentColor 조합을 사용

- 머티리얼에서는 ContentAlpha 객체에 의해 모델링된 일부 표준 알파 값(high, medium, disabled)을 지정

- MaterialTheme은 LocalContentAlpha의 기본값을 ContentAlpha.high로 설정함

 

결과

 

실제 응용 예시

중요도가 투명도로 전달이 됨

 

 

4) 어두운 테마

Compose에서 MaterialTheme Composable에 다양한 Colors 세트를 제공하고

테마를 통해 색상을 사용하여 light theme 및 dark theme를 구현합니다.

예제1.

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

- isSystemInDarkTheme()로 어두운 테마를 사용할지 여부를 정하고 있습니다.

- true 일떄 기기 테마 설정을 쿼리하여 darkTheme의 기본값을 가져옵니다.

 

예제2.

val isLightTheme = MaterialTheme.colors.isLight

- DarkTheme를 구현할 때 현재 Colors가 밝은지 또는 어두운지 확인할 수 있습니다.

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

 

예제3.

Surface(
    elevation = 2.dp,
    color = MaterialTheme.colors.surface, // color will be adjusted for elevation
    /*...*/
) { /*...*/ }

- 머티리얼에서 고도가 높은 Dark Theme의 표시 경로는 배경을 밝게 하는 고도 오버레이를 수신합니다.

- 이러한 오버레이는 어두운 색상을 사용할 때 Surface Composable에 의해 자동 구현됩니다.

 

 

- 카드 및 하단 탐색은  surface 색상이 지정되어 있지만 더 높은 고도에 있기 때문에 색상이 약간 더 밝음

 

 

5) 머티리얼 색상 확장

  val Colors.snackbarAction: Color
        @Composable get() = if (isLight) Blue200 else Blue700

- 색상 세트를 확장해야 한다면 위와 같이 자체 색상 시스템을 구현하거나 확장을 추가할 수 있음

 

 

2. 서체

 

https://material.io/design/typography/the-type-system.html#type-scale

 

Material Design

Build beautiful, usable products faster. Material Design is an adaptable system—backed by open-source code—that helps teams build high quality digital experiences.

material.io

머티리얼 디자인은은 위 링크처럼 유형 시스템을 정의해서

의미론적으로 이름이 지정된 소수의 스타일을 사용하도록 권장함

 

Compose는 Typography, TextStyle  글꼴 관련 클래스를 사용하여 유형 시스템을 구현합니다. 

-Typography 생성자는 각 스타일의 기본값을 제공하므로 맞춤 설정하지 않으려는 스타일은 생략가능

 

val Rubik = FontFamily(
    Font(R.font.rubik_regular),
    Font(R.font.rubik_medium, FontWeight.W500),
    Font(R.font.rubik_bold, FontWeight.Bold)
)

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, /*...*/)


참고: Compose는 현재 Android의 다운로드 가능한 글꼴 기능을 지원하지 않지만 번들 글꼴 리소스를 지원합니다.

https://developer.android.com/guide/topics/resources/font-resource

 

글꼴 리소스  |  Android 개발자  |  Android Developers

글꼴 리소스는 앱에서 사용할 수 있는 맞춤 글꼴을 정의합니다. 글꼴은 개별 글꼴 파일 또는 글꼴 모음이라고 하는 글꼴 파일 모임일 수 있으며 XML로 정의됩니다. 또한, XML로 글꼴을 정의하는 방

developer.android.com

 

 

텍스트 스타일 사용

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

 

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

 

3. 도형

머티리얼은 도형 시스템을 정의합니다.

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

 

Compose는 Shapes 클래스를 통해 도형 시스템을 구현합니다.

이 클래스를 사용하면 각 카테고리의 CornerBasedShape를 지정할 수 있습니다.

예제

val Shapes = Shapes(
    small = RoundedCornerShape(percent = 50),
    medium = RoundedCornerShape(0f),
    large = CutCornerShape(
        topStart = 16.dp,
        topEnd = 0.dp,
        bottomEnd = 0.dp,
        bottomStart = 16.dp
    )
)

MaterialTheme(shapes = Shapes, /*...*/)

- 많은 구성요소가 기본적으로 이러한 도형을 사용합니다.

- UI 사이즈 별로 도형 정의가 나뉨

   -  small => Button,TextField 등등.., medium => AlertDialog 등등.. , large => ModalDrawer 등등.. 

 

 

도형 사용

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

Surface(
    shape = MaterialTheme.shapes.medium, /*...*/
) {
    /*...*/
}

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

4. 구성요소 스타일

- Compose에는 구성요소 스타일에 대한 명시적인 개념이 없음

(자체 Composable을 생성하여 이 기능을 제공하기 때문입니다.)

 

아래 예제와 같은 방식으로 스타일을 만들 수 있음

 

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

 - 고유의 Composable 함수로 버튼을 래핑하고 변경하려는 매개변수를 직접 설정하며 포함하는 Composable에 매개변수로 다른 매개변수를 노출합니다.

5. 맞춤 디자인 시스템

머티리얼은 권장되는 디자인 시스템이지만 이 시스템뿐만 아니라

동일한 방식으로 자체 디자인 시스템을 만드는 것이 전적으로 가능

이 문서에서는 다룰 수 있는 범주를 벗어낫기 때문에 개발자 스스로가 개척해야함

 

자세한 내용은 아래 링크들 참고해서 커스텀 해볼것 

 

https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/src/commonMain/kotlin/androidx/compose/material/MaterialTheme.kt?hl=ko 

 

https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/src/commonMain/kotlin/androidx/compose/material/MaterialTheme.kt?hl=ko

 

cs.android.com

https://developer.android.com/reference/kotlin/androidx/compose/runtime/CompositionLocal?hl=ko 

 

CompositionLocal  |  Android 개발자  |  Android Developers

 

developer.android.com

https://developer.android.com/reference/kotlin/androidx/compose/runtime/package-summary?hl=ko#CompositionLocalProvider(kotlin.Array,kotlin.Function0) 

 

androidx.compose.runtime  |  Android 개발자  |  Android Developers

 

developer.android.com

https://github.com/android/compose-samples/tree/main/Jetsnack

 

android/compose-samples

Official Jetpack Compose samples. Contribute to android/compose-samples development by creating an account on GitHub.

github.com

 

6.정리 

 

- 기본적으로 Compose는 머티리얼 디자인을 테마로 자신의 앱을 만들 수 있도록 제공해주는 편임

- 색상,도형,서체 등등 손쉽게 머티리얼 디자인을 따라갈 수 있도록 좋게 지원을 함 

- 가능하면 머티리얼 디자인 뿐만 아니라 맞춤 디자인 시스템을 갖출수 있음

 

Compose를 통해서 더 쉽게 머티리얼 디자인을 따라갈 수 있도록 되어가는것 같습니다. 기존 xml로 했을 때 머티리얼 디자인 가이드를 보면서 안드로이드에서 완전 알맞게 지원을 해주는편이라긴 보다 이런 디자인 가이드는 너가 알아서 따라해라 느낌에 가까웠다면 이젠 본격적으로 머티리얼 디자인을 누구나 쉽게 잘 적용할 수 있을 것 같네요.

 

이상 컴포즈의 테마적용편을 마무리 하겠습니다.

 

 

 

 

이전 Compose 내용 정리

https://gift123.tistory.com/33?category=967702 

 

안드로이드 개발 (8) Compose 이해 정리

이번 포스팅부터 Compose에 대해 차근히 파헤쳐 가보겠습니다. Android Compose 공식 문서를 보면서 정리한 내용들 입니다. https://developer.android.com/jetpack/compose/mental-model?hl=en Compose 이해  |..

gift123.tistory.com

https://gift123.tistory.com/34?category=967702 

 

안드로이드 개발 (9) Compose 상태 관리

jetpack compose 에 한창 포스팅 중입니다. https://gift123.tistory.com/33 안드로이드 개발 (8) Compose 이해 정리 이번 포스팅부터 Compose에 대해 차근히 파헤쳐 가보겠습니다. Android Compose 공식 문서를..

gift123.tistory.com

 

https://gift123.tistory.com/38?category=967702 

 

안드로이드 개발 (10) Compose Composable Lifecycle

안녕하세요 Loner 입니다. 오늘은 Compose의 컴포저블 라이프사이클 공부를 정리해 봤습니다. 아래 문서를 정리한 내용입니다. https://developer.android.com/jetpack/compose/lifecycle?hl=en 컴포저블 수명 주..

gift123.tistory.com

https://gift123.tistory.com/39?category=967702 

 

안드로이드 개발 (11) Compose Side-effects

https://developer.android.com/jetpack/compose/side-effects#state-effect-use-cases Compose의 부수 효과  | Jetpack Compose  | Android Developers 컴포저블에는 부수 효과가 없어야 합니다. 하지만 앱의..

gift123.tistory.com

https://gift123.tistory.com/41?category=967702 

 

안드로이드 개발 (13) Layout in Compose 1편

지금까지 Compose에 대해 composable 라이프사이클, Compose 내부흐름 , Composition, recompostion, Sdie-effects 활용방법에 대한 원론 방법에 알았다면 이제 실질적으로 Compose로 Layout을 어떻게 구성하는지..

gift123.tistory.com

https://gift123.tistory.com/42?category=967702 

 

안드로이드 개발 (14) Layout in Compose 2편

1편 정리 https://gift123.tistory.com/41 안드로이드 개발 (13) Layout in Compose 1편 지금까지 Compose에 대해 composable 라이프사이클, Compose 내부흐름 , Composition, recompostion, Sdie-effects 활용방..

gift123.tistory.com