buildAnnotatedString이란?
buildAnnotatedString은 AnnotatedString 객체를 만드는 inline function이다.
inline fun buildAnnotatedString(builder: (Builder).() -> Unit): AnnotatedString =
Builder().apply(builder).toAnnotatedString()
buildAnnotatedString을 이용해 만들어진 AnnotatedString은 하나의 Text 안에서 여러 스타일을 적용할 수 있도록 하는 정보를 담은 객체로 AnnotatedString 속에는 텍스트의 스타일에 대한 정보를 담은 text, spanStyles, paragraphStyles, annotations 객체들이 저장되어 있다.
class AnnotatedString internal constructor(
val text: String,
val spanStyles: List<Range<SpanStyle>> = emptyList(),
val paragraphStyles: List<Range<ParagraphStyle>> = emptyList(),
internal val annotations: List<Range<out Any>> = emptyList()
)
Text 컴포저블의 text 파라미터로 AnnotatedString을 넘기면 text, spanStyles, paragraphStyles, annotations 들이 사용되어 텍스트가 스타일링된다. 즉, AnnotatedString은 하나의 Text 컴포저블의 특정 단어를 스타일링 하거나 단락을 스타일링 할 때 사용된다.
예를 들어 아래와 같이 "Hello Kotlin World"의 Hello에만 강조표시를 주고 싶은 경우 아래와 같이 하나의 Text 안에서 강조 표시가 가능해진다.
buildAnnotatedString 사용법
buildAnnotatedString은 inline fun으로 AnnotatedString을 만들어내는 빌더를 인자로 받는다.
inline fun buildAnnotatedString(builder: (Builder).() -> Unit): AnnotatedString =
Builder().apply(builder).toAnnotatedString()
이번 글의 목표는 이 빌더를 만드는 방법을 아는 것이다.
builder: (Builder).() -> Unit
위와 같이 빌더는 함수형으로 인자를 받으며, 함수 내부에서는 메서드를 써서 AnnotatedString을 build하기 위한 옵션들이 있음을 알 수 있다.
builder에 String 추가하기
builder에 String을 추가하는 방법은 간단하다. 마치 StringBuilder 같이 append를 이용해 String을 추가할 수 있다.
fun append(text: String) {
this.text.append(text)
}
예를 들어 "Hello ", "Kotlin", "World ", 세 단어를 추가한다고 해보자. 다음과 같이 append를 이용해 추가할 수 있다.
@Preview(showBackground = true, widthDp = 200, heightDp = 200)
@Composable
fun KotlinWorldTextBuildAnnotatedString1() {
Column(
modifier = Modifier
.fillMaxSize()
) {
Text(
text = buildAnnotatedString {
append("Hello ")
append("Kotlin ")
append("World")
}
)
}
}
추가한 String에 withStyle이용해 Style 주기
이번에는 위에서 추가한 String들에 Style을 주도록 해보자. 다양한 방법이 있지만, 이번 글에서는 직관적으로 스타일을 줄 수 있는 withStyle을 이용한다.
inline fun <R : Any> Builder.withStyle(
style: SpanStyle,
crossinline block: Builder.() -> R
): R {
val index = pushStyle(style)
return try {
block(this)
} finally {
pop(index)
}
}
withStyle은 SpanStyle이라 부르는 Text의 스타일을 정의해놓은 객체를 인자로 받고 withStyle 블록 속의 String에 해당 스타일을 적용할 수 있도록 하는 function이다. SpanStyle 객체에는 fontSize, fontWeight, fontStyle, fontFamily 등 앞선 장들에서 보았던 모든 Text관련 스타일을 정의할 수 있다.
*웹 프론트 프로그래밍의 span 블록과 같다.
이번 글에서는 간단히 Hello의 fontSize만 32sp로 키우고 fontWeight에 bold를 적용시키도록 하자.
@Preview(showBackground = true, widthDp = 200, heightDp = 200)
@Composable
fun KotlinWorldTextBuildAnnotatedString() {
Column(
modifier = Modifier
.fillMaxSize()
) {
Text(
text = buildAnnotatedString {
withStyle(
SpanStyle(
fontSize = 32.sp,
fontWeight = FontWeight.Bold
)
) {
append("Hello ")
}
append("Kotlin")
append("World")
}
)
}
}
위의 코드를 수행하면 아래와 같은 결과를 얻을 수 있다.
이번에는 Kotlin의 색상을 파란색으로 바꾸고 Italic체로 바꾸어보도록 하자.
@Preview(showBackground = true, widthDp = 200, heightDp = 200)
@Composable
fun KotlinWorldTextBuildAnnotatedString() {
Column(
modifier = Modifier
.fillMaxSize()
) {
Text(
text = buildAnnotatedString {
withStyle(
SpanStyle(
fontSize = 32.sp,
fontWeight = FontWeight.Bold
)
) {
append("Hello ")
}
withStyle(
SpanStyle(
color = Color.Blue,
fontStyle = FontStyle.Italic
)
) {
append("Kotlin")
}
append("World")
}
)
}
}
이러한 방식으로 다양한 스타일을 조합하여 빌더 방식으로 Text를 스타일링 할 수 있다.