티스토리 뷰

커스텀 테마를 사용하는 방법을 알아보자.

커스텀 테마 사용하기

먼저 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

 

Compose 기본사항  |  Jetpack Compose for Android Developers - Compose essentials

Jetpack Compose를 처음으로 사용해 보세요. 구성 가능한 함수, 기본 레이아웃 및 상태, Material Design, 목록, 애니메이션에 관해 알아보세요.

developer.android.com

2022.12.14 - [Android/Jetpack Compose] - [Android] compose basic state (상태의 기본 내용 정리)

2022.10.15 - [Android/Google Play] - 구글 플레이스토어 Android 11(target API 31) 으로 마이그레이션

2022.10.09 - [Android/Jetpack Compose] - [Android] This annotation should be used with the compiler argument '-opt-in=kotlin.RequiresOptIn' 해결하기

댓글
최근에 올라온 글
최근에 달린 댓글
네이버 이웃추가
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함