[Compose] 한 텍스트에 각각 다른 스타일 적용하기

빙기·2026년 5월 5일

안드로이드

목록 보기
1/1

결과물

적용하기

한 텍스트 컴포저블 내에 각각 다른 스타일을 적용하려면 buildAnnotatedString과 withStyle, append를 사용한다.

텍스트의 text 부분에 buildAnnotatedString으로 특수한 스타일을 적용하고 싶은 부분을 withStyle+append로, 기본 스타일을 적용할 부분은 그냥 append로 설정한다.

Text(
	text = buildAnnotatedString {
    	// withStyle로 특수한 스타일을 추가로 적용한다.
		withStyle(SpanStyle(color = selected.color)) { append("포인트 컬러") }
        // withStyle로 감싸지 않으면 Text에 적용한 스타일을 그대로 적용한다.
		append("를 선택하세요")
	},
	style = MaterialTheme.typography.headlineSmall.copy(
    	fontWeight = FontWeight.Bold
	),
	color = Color.White
)

withStyle로 감싸지 않은 append 텍스트는 Text 컴포저블에서 설정한 style을, withStyle로 감싼 텍스트는 Text 컴포저블에서 설정한 style에 SpanStyle로 지정한 부분만 바뀐다.

SpanStyle을 통해 다음과 같이 여러 스타일을 지정할 수 있다.

public constructor SpanStyle(
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontWeight: FontWeight? = null,
    fontStyle: FontStyle? = null,
    fontSynthesis: FontSynthesis? = null,
    fontFamily: FontFamily? = null,
    fontFeatureSettings: String? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    baselineShift: BaselineShift? = null,
    textGeometricTransform: TextGeometricTransform? = null,
    localeList: LocaleList? = null,
    background: Color = Color.Unspecified,
    textDecoration: TextDecoration? = null,
    shadow: Shadow? = null,
    platformStyle: PlatformSpanStyle? = null,
    drawStyle: DrawStyle? = null
)

추가 적용 - 컬러 변경 애니메이션

포인트 컬러를 선택할 때마다 글씨 색상도 바뀌는데, 끊기듯 확 변하는 게 어색해보여서 전환 애니메이션을 추가했다.

// 선택된 컬러 변경 시 0.5초 동안 부드럽게 색상 전환
val animatedColor by animateColorAsState(
    targetValue = selected.color,
    animationSpec = tween(durationMillis = 500),
    label = "colorAnimation"
)

포인트 컬러로 강조된 텍스트의 color를 animatedColor로 바꾸면 애니메이션이 적용된다.

...
withStyle(SpanStyle(color = animatedColor)) {
...

전체 코드

// 색상 데이터 클래스
enum class AccentColor(val color: Color) {
    Red(Color(0xFFEF5350)),
    Blue(Color(0xFF42A5F5)),
    Green(Color(0xFF66BB6A)),
    Yellow(Color(0xFFFFCA28)),
    Purple(Color(0xFFAB47BC))
}

// 포인트 색상 선택 컴포저블
@Composable
fun AccentColorPicker() {
    val colorScrollState = rememberScrollState()
    var selected by remember { mutableStateOf(AccentColor.Blue) }

    // 색상 변경 애니메이션
    val animatedColor by animateColorAsState(
        targetValue = selected.color,
        animationSpec = tween(durationMillis = 500),
        label = "colorAnimation"
    )

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
    ) {
        Text(
            text = buildAnnotatedString {
                withStyle(SpanStyle(color = selected.color)) {
                    append("포인트 컬러")
                }
                append("를 선택하세요")
            },
            style = MaterialTheme.typography.headlineSmall.copy(
                fontWeight = FontWeight.Bold
            ),
            color = Color.White
        )

        Spacer(Modifier.height(32.dp))

        // 색상 선택
        Row(
            horizontalArrangement = Arrangement.spacedBy(12.dp),
            modifier = Modifier.horizontalScroll(colorScrollState)
        ) {
            AccentColor.entries.forEach { accent ->
                val isSelected = accent == selected

                Box(
                    modifier = Modifier
                        .size(44.dp)
                        .clip(CircleShape)
                        .background(accent.color)
                        .then(
                            if (isSelected)
                                Modifier.border(2.dp, Color.White, CircleShape)
                            else Modifier
                        )
                        .clickable { selected = accent }
                )
            }
        }
    }
}

0개의 댓글