Jetpack Compose를 시작하기 위한 강의는 구글에서 제공한다.
레이아웃을 어떻게 만들지는 한 번만 따라해도 어느정도 각이 나온다. 어떻게 디자인하는지 알려주는 강의는 너무 많다. 하지만 중요한건 Integration! 앞으로 블로그에서 다룰 Jetpack Compose 관련 주제가 바로 Integration이 될 것이다. 어떻게 내 프로젝트에 통합시킬 수 있을지!
Theming
그 첫번째로 테마(Theme)와 스타일에 관해서 알아보려고한다.
Jetpack Compose에서 아주 쉽게 Material Design을 적용시킬 수 있다고는 하지만, 디자이너들은(93% 확률로 아이폰을 이용중) 우리에게 Material Design을 던져주지 않는다. 앱 고유의 스타일을 어떻게 확립하고 적용시킬 수 있는지 알아보자.
Colors
기존에는 앱에서 자주쓰는 색상들을 res > colors.xml
에 저장해왔다. 이제는 Colors.kt
같은 kotlin 파일에 저장한다.
github에서 높은 Star를 받은 Jetpack Compose 프로젝트 몇개를 보니 패키지명 > ui > Color.kt
혹은 패키지명 > ui > theme > Color.kt
정도의 경로로 정리하고 있다.
내용은 대충 이렇다.
import androidx.compose.ui.graphics.Color val louBlue = Color(0xFF407FFC) val purple500 = Color(0xFF6200EE) val purple700 = Color(0xFF3700B3) val teal200 = Color(0xFF03DAC5)
Theme
마찬가지로 theme.xml
에 저장하고는 했었던 내용들을 Theme.kt
에 작성할 수 있다. darkColors
나 lightColors
는 각각 다크테마와 라이트테마 기준으로 만들어지며, 값을 주지 않으면 기본 값을 채운다. 반대로 Colors는 테마를 처음부터 재정의하기 때문에 모든 parameter를 다 채워주어야한다.
여기에는 당연하게도 아까 Colors.kt
에 정의했던 색깔들을 불러올 수 있다.
import androidx.compose.material.Colors import androidx.compose.material.darkColors import androidx.compose.material.lightColors import androidx.compose.ui.graphics.Color private val DarkColorPalette = darkColors( primary = louBlue, primaryVariant = louBlue, secondary = teal200, background = Color.Black, surface = Color.DarkGray ) private val LightColorPalette = lightColors( primary = louBlue, primaryVariant = louBlue, secondary = louBlue, background = Color.White ) private val customColorPalette = Colors( primary = purple500, primaryVariant = purple500, secondary = purple700, secondaryVariant = purple700, background = Color.White, surface = Color.White, error = Color.White, onPrimary = Color.Black, onSecondary = Color.Black, onBackground = Color.Black, onSurface = Color.Black, onError = Color.White, isLight = true )
Theme.kt
를 작성했다면, 이 모든 테마를 Composable
함수로 래핑하여 적용가능한 형태로 만들어야한다. 똑같이 Theme.kt
파일에다 작성해주면 된다. @Composable
은 Annotation processor처럼 보일 수 있지만 사실은 suspend 키워드 처럼 함수의 타입을 정의하는 language keyword다. 이 사실을 숙지하면 @Composable () -> Unit
같은 코드가 자연스럽게 보이기 시작할 것 이다.
나는 LouAppTheme라는 테마를 정의했고, 시스템이 다크모드냐 아니냐에 따라 colors를 정의하고 MaterialTheme을 만들어서 해당 컬러팔레트를 인자로 넘겨주었다.
@Composable fun LouAppTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { val colors = if (darkTheme) DarkColorPalette else LightColorPalette MaterialTheme( colors = colors, content = content ) }
MaterialTheme
은 사실 이렇게 생긴 Composable 함수다. 이걸보면 "shape나 typography도 같이 정의해서 넣을 수 있구나
이 글의 어딘가에 쉐이프랑 폰트 정의를 얘기할꺼구나~"를 직감할 수 있다.
@Composable fun MaterialTheme( colors: Colors = MaterialTheme.colors, typography: Typography = MaterialTheme.typography, shapes: Shapes = MaterialTheme.shapes, content: @Composable () -> Unit ) { ... }
나를 포함하여 추가적인 궁금증이 드시는 분들을 위해... 방금 정의한 Theme은 이렇게 사용할 수 있다.
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { LouAppTheme { // TODO Composable... // MaterialTheme.colors.primary 로 접근가능 } } } }
Typography
올 것이 왔군? Typography.kt
파일에 타이포 그래피를 정의할 수 있다. 커스텀 폰트를 사용하기 위해서 앱의 res > font
에 사용할 font를 넣는 방식은 같다. 나는 샘플로 Noto sans를 다운받아서 앱에 적용하려한다.
val NotoFontFamily = FontFamily( Font(R.font.noto_sans_cjk_kr_regular), Font(R.font.noto_sans_cjk_kr_medium, FontWeight.Medium), Font(R.font.noto_sans_cjk_kr_bold, FontWeight.Bold) )
Typography는 이렇게 정의할 수 있다. defaultFontFamily는 따로 FontFamily가 없다면 생략가능하다.
val typography = Typography( defaultFontFamily = NotoFontFamily, h1 = TextStyle( fontWeight = FontWeight.Light, fontSize = 96.sp, letterSpacing = 1.2.sp ) )
앱의 각 구성요소마다 이렇게 텍스트 스타일을 미리 지정해둘 수 있다. 정의 가능한 요소들은 아래 사진과 같다.

Shape
윈도우 UI의 타일 디자인처럼 모든 버튼이 각져있는 앱은 드물다. (미안해 마소...!!ㅋㅋㅋ) 다들 저마다의 Radius를가진 둥글둥글한 버튼들이나, 카드 컴포넌트를 이용한다.

원래는 Shape들을 drawables
아래에 xml
로 만들어서 배경으로 넣어주고...했는데 Compose에는 Shape라는 파라미터를 정의해주면 알아서 둥글게 처리된다. 통일감있는 둥글기 처리를 위해 이 Shape의 Radius값들도 테마로서 정의할 수 있다. 이제 대충 Shape.kt
정도에 저장하는게 custom임을 아셨으리...
val Shapes = Shapes( small = RoundedCornerShape(4.dp), medium = RoundedCornerShape(8.dp), large = RoundedCornerShape(16.dp) )
아까 잠깐 MaterialTheme에서 보았던 것 처럼 테마에서 파라미터로 넘겨서 정의하고, Composable 함수에서 MaterialTheme.shapes.large
이렇게 접근해서 적용시킬 수 있다.
참고자료
https://medium.com/androiddevelopers/under-the-hood-of-jetpack-compose-part-2-of-2-37b2c20c6cdd
https://infinum.com/the-capsized-eight/jetpack-compose-framework
'프로그래밍 > Android' 카테고리의 다른 글
[안드로이드] Koin에서 Hilt로, Hilt 배워보기 (0) | 2021.10.09 |
---|---|
[안드로이드] 카카오웹툰 앱에서 쓴 오픈소스 라이브러리를 알아보자 (1) | 2021.09.07 |
Android Studio 한글 깨짐 현상 해결법 (Arctic Fox) (0) | 2021.09.01 |
[Jetpack Compose] 왜 Jetpack Compose가 나와야만 했을까? (0) | 2021.08.30 |
[안드로이드] Retrofit2 오프라인 캐시 구현하기 (Offline cache interceptor) (0) | 2021.08.30 |