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 |