커스텀 테마를 사용하는 방법을 알아보자.
커스텀 테마 사용하기
먼저 JetnewsTheme 라는 이름으로 테마를 사용할 것이므로 테마를 아래와 같이 정의 해준다.
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
MaterialTheme(content = content)
}
MaterialTheme
를 단순 감싸고 있으며, 이후에 MaterialTheme
의 생성자 옵셔널한 파라미터를 전달하면서 테마를 커스텀하는 방식으로 사용할 수 있다.
@Composable
fun Home() {
val featured = remember { PostRepo.getFeaturedPost() }
val posts = remember { PostRepo.getPosts() }
JetnewsTheme {
Scaffold(
topBar = { AppBar() }
) { innerPadding ->
메인 화면인 Home
컴포저블을 위에서 정의하였던 테마를 사용하도록 수정한다.
@Preview("Featured Post")
@Composable
private fun FeaturedPostPreview() {
val post = remember { PostRepo.getFeaturedPost() }
JetnewsTheme {
FeaturedPost(post = post)
}
}
프리뷰도 정의하여 미리 볼 수 있도록 만들자.
테마 색상 설정
val Red700 = Color(0xffdd0d3c)
val Red800 = Color(0xffd00036)
val Red900 = Color(0xffc20029)
먼저 테마의 색상을 커스텀 하기 위해서 전역 필드로 컬러 값을 정의해준다.
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
MaterialTheme(
colors = LightColors,
content = content
)
}
private val LightColors = lightColors(
primary = Red700,
primaryVariant = Red900,
onPrimary = Color.White,
secondary = Red700,
secondaryVariant = Red900,
onSecondary = Color.White,
error = Red800
)
이후 컬러셋을 하나 생성하고, 위에서 정의했던 컬러를 사용하여, MaterialTheme
의 colors 인자로 전달한다.
Typography 설정
val Montserrat = FontFamily(
Font(R.font.montserrat_regular),
Font(R.font.montserrat_medium, FontWeight.W500),
Font(R.font.montserrat_semibold, FontWeight.W600)
)
val Domine = FontFamily(
Font(R.font.domine_regular),
Font(R.font.domine_bold, FontWeight.Bold)
)
글자 스타일 정의를 위해 FontFamily 를 사용한다.
@Composable
fun JetnewsTheme(content: @Composable () -> Unit) {
MaterialTheme(
colors = LightColors,
typography = JetnewsTypography,
shapes = JetnewsShapes,
content = content
)
}
MaterialTheme
의 typography 로 전달하면 적용 끝.
Text(
text = post.title,
style = MaterialTheme.typography.h6,
modifier = padding
)
Text(
text = post.metadata.author.name,
style = MaterialTheme.typography.body2,
modifier = padding
)
실제로는 style 에 전달하여 커스텀 스타일을 사용가능하다.
다크 테마 사용하기
private val DarkColors = darkColors(
primary = Red300,
primaryVariant = Red700,
onPrimary = Color.Black,
secondary = Red300,
onSecondary = Color.Black,
error = Red200
)
다크 테마에 사용될 darkColors
를 정의해주고,
@Composable
fun JetnewsTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
MaterialTheme(
colors = if (darkTheme) DarkColors else LightColors,
typography = JetnewsTypography,
shapes = JetnewsShapes,
content = content
)
}
시스템 설정이 다크테마인 경우에 다크컬러셋을 사용하도록 수정하자.
다크 모드 프리뷰
@Preview("Featured Post • Dark")
@Composable
private fun FeaturedPostDarkPreview() {
val post = remember { PostRepo.getFeaturedPost() }
JetnewsTheme(darkTheme = true) {
FeaturedPost(post = post)
}
}
프리뷰에서 다크모드를 확인할 수 있도록 추가한다.
Surface 로 배경색 지정하기
@Composable
fun Header(
text: String,
modifier: Modifier = Modifier
) {
Surface(
color = MaterialTheme.colors.onSurface.copy(alpha = 0.1f),
contentColor = MaterialTheme.colors.primary,
modifier = modifier
) {
Text(
text = text,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp)
)
}
}
배경색을 지정할 때는 Surface 를 사용하는 것이 권장된다. 테마의 컬러를 사용하고 있으며 알파 값만 수정하기 위해 copy 메서드를 활용하여 개별적으로 수정된 색상을 사용한다.
CompositionLocalProvider
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(
text = text,
modifier = modifier
)
}
콘텐츠 알파를 사용하여 추천 게시물의 정보 계층 구조를 명확히 합니다. Home.kt의 PostMetadata 컴포저블에서 메타데이터 medium을 강조
primarySurface
backgroundColor = MaterialTheme.colors.primarySurface
primarySurface 를 사용하여 다크/라이트 테마일 때 적절한 색상 사용
withStyle 로 개별 스타일 적용
val text = buildAnnotatedString {
append(post.metadata.date)
append(divider)
append(stringResource(R.string.read_time, post.metadata.readTimeMinutes))
append(divider)
val tagStyle = MaterialTheme.typography.overline.toSpanStyle().copy(
background = MaterialTheme.colors.primary.copy(alpha = 0.1f)
)
post.tags.forEachIndexed { index, tag ->
if (index != 0) {
append(tagDivider)
}
withStyle(tagStyle) {
append(" ${tag.uppercase(Locale.getDefault())} ")
}
}
}
buildAnnotatedString 에서 withStyle 로 개별 배경 스타일 주기.
스판 스타일 적용과 비슷하게 withStyle 로 특정 텍스트에 특정 스타일을 적용할 수도 있다. 여기서는 태그 글씨 뒷 배경으로 연한 색상을 깔아준다.
Modifier.clip
Image(
painter = painterResource(post.imageThumbId),
modifier = Modifier.clip(shape = MaterialTheme.shapes.small),
contentDescription = null
)
클립 효과를 주어 이미지 코너를 잘라 보여줄 수 있다.
참고로 현재 커스텀 테마 Shapes 는 아래와 같이 적용되어 있다.
val JetnewsShapes = Shapes(
small = CutCornerShape(topStart = 8.dp),
medium = CutCornerShape(topStart = 24.dp),
large = RoundedCornerShape(8.dp)
)
Reference
2022.12.14 - [Android/Jetpack Compose] - [Android] compose basic state (상태의 기본 내용 정리)
2022.10.15 - [Android/Google Play] - 구글 플레이스토어 Android 11(target API 31) 으로 마이그레이션
'Android > Jetpack Compose' 카테고리의 다른 글
[Jetpack Compose] 애니메이션 활용 및 기본 내용 정리 (0) | 2022.12.17 |
---|---|
[Jetpack Compose] view + xml 기반에서 컴포즈로 마이그레이션 (1) | 2022.12.16 |
[Jetpack Compose] compose basic state (상태의 기본 내용 정리) (1) | 2022.12.14 |
[Android] This annotation should be used with the compiler argument '-opt-in=kotlin.RequiresOptIn' 해결하기 (0) | 2022.10.09 |
[Android] GDG Jetpack compose 코드랩 수료 후기 (feat. 굿즈) (0) | 2021.12.18 |