텍스트 하이퍼링크 기능을 Compose의 ClickableText로 구현하셨나요?
2024년 9월 4일 출시된 androidx.compose.foundation:foundation-*:1.7.0 버전부터 텍스트 하이퍼링크를 쉽게 구현할 수 있는 LinkAnnotation
을 stable 하게 지원합니다.
ClickableText은 이제 그만
LinkAnnotation을 알아보기 전에 ClickableText를 잠시 살펴보시면 LinkAnnotation의 장점을 쉽게 알 수 있습니다
하나의 문자열에서 2개 이상의 하이퍼링크가 있으면 사용자의 클릭한 위치 또는 문자열을 알아야 구분할 수 있을 겁니다. 그런 목적에서 ClickableText는 클릭한 문자의 위치를 의미하는 character's offset 값이 인자로 들어오는 onClick 람다를 제공해주고 있었습니다
val annotatedText = buildAnnotatedString {
append("블로그 ")
pushStringAnnotation(
tag = "URL", annotation = "https://jaeryo2357.tistory.com/"
)
withStyle(
style = SpanStyle(
color = Color.Blue,
fontWeight = FontWeight.Bold,
textDecoration = TextDecoration.Underline
)
) {
append("방문하기")
}
pop()
}
ClickableText(text = annotatedText, onClick = { offset ->
// 클릭된 위치에 "URL"태그가 있는지 확인하고, 있으면 클릭이벤트 수행
annotatedText.getStringAnnotations(
tag = "URL", start = offset, end = offset
).firstOrNull()?.let { annotation ->
Log.d("Clicked URL", annotation.item)
}
})
ClickableText로 텍스트 하이퍼링크를 구현한 코드입니다. 핵심은 pushStringAnnotation을 통해 특정 위치에 tag와 url을 등록하고, offset 범위에 등록된 tag가 있다면 작업을 수행합니다.
예시 코드에서는 나름 간단해 보이지만, 다음 같은 단점이 존재한다고 생각합니다. 하나의 문자열에서 하이퍼링크가 여러 개라면 더 많이 느껴지겠죠
1. tag 등록과 style 지정하는 위치가 동일하도록 신경 써서 관리해야 한다.
2. 하이퍼링크를 등록, 처리하는 곳이 이중화되어 있다.
이러한 단점은 하나의 문자열에 하이퍼링크가 많아지면 더욱 느껴지실 것이라고 생각이 듭니다.
LinkAnnotation
val annotatedText = buildAnnotatedString {
append("블로그 ")
withLink(
LinkAnnotation.Url(
url = "https://jaeryo2357.tistory.com/",
styles = TextLinkStyles(
style = SpanStyle(
color = Color.Blue,
fontWeight = FontWeight.Bold,
textDecoration = TextDecoration.Underline
)
),
linkInteractionListener = { annotation ->
if (annotation is LinkAnnotation.Url) {
Log.d("Clicked URL", annotation.url)
}
}
)
) {
append("방문하기")
}
}
Text(
text = annotatedText
)
LinkAnnotation으로 구현한 텍스트 하이퍼링크 기능 코드입니다. 간단해진 것이 느껴지시나요?? 저는 LinkAnnotation으로 등록과 처리를 한 번에 할 수 있다는 점이 가장 큰 차이점으로 느껴집니다.
LinkAnnotation 종류
LinkAnnotation.Url
class Url(
val url: String,
override val styles: TextLinkStyles? = null,
override val linkInteractionListener: LinkInteractionListener? = null
) : LinkAnnotation() {
...
}
LinkAnnotation.Clickable이랑 비교하면 linkInteractionListener 인자에서 큰 차이점이 있습니다.
LinkAnnotation.Url에서 LinkInteractionListener 값이 기본 값인 null로 설정을 하면, 하이퍼링크를 클릭되었을 때 Compose의 UrlHandler에 의해 입력한 url 주소로 이동을 시도합니다. 따라서 url 인자에 되도록 실제 주소를 입력하는 것이 좋겠죠?
LinkAnnotation.Clickable
class Clickable(
val tag: String,
override val styles: TextLinkStyles? = null,
override val linkInteractionListener: LinkInteractionListener?
) : LinkAnnotation() {
LinkAnnotation.Clickable 생성자 코드입니다. linkInteractionListener 인자가 필수값으로 되어있는 부분이 가장 큰 차이점 같네요. 하이퍼링크가 아닌 문자열에서 특정 단어의 클릭을 감지하기 위한 목적으로 사용하면 될 것 같습니다.
TextLinkStyles
LinkAnnotation을 위한 텍스트 스타일을 지정하는 클래스도 만들어졌네요.
@Immutable
class TextLinkStyles(
val style: SpanStyle? = null,
val focusedStyle: SpanStyle? = null,
val hoveredStyle: SpanStyle? = null,
val pressedStyle: SpanStyle? = null
) {
...
}
뷰 상태(normal, pressed, focused)에 따른 스타일 지정을 지원하는 것으로 보입니다. compose-web을 위한 hoveredStyle도 지원해 주네요
'Android > Compose' 카테고리의 다른 글
[Android] Space Hoisting, Compose에서 여백을 주는 방법 (0) | 2023.02.16 |
---|---|
[Android] Compose BackdropScaffold 적용해보기 (0) | 2023.01.19 |
[Android] Compose PreviewParameterProvider (2) | 2022.09.22 |
[Android] Compose - Accompanist Inset (0) | 2022.09.14 |
[Android] Bottom Navigation Bar UI with Compose - (1) (0) | 2022.06.06 |