Checkbox 아이콘을 텍스트의 원하는 위치로 정렬 하는 방법 (Jetpack Compose)
- 텍스트 가운데에 아이콘 정렬 쉽게 하는 방법
- 텍스트 첫 번째 줄, 마지막 줄에 아이콘 정렬 쉽게 하는 방법
- 아무리 찾아도 Stack Overflow에 없는 내용?
안녕하세요.
헤이딜러 안드로이드팀의 윤영직입니다.
🎉 드디어 헤이딜러에 Jetpack Compose가 도입되었습니다. 🎉
앞으로 Jetapck Compose를 사용한 문제 해결 사례를 공유 할 예정입니다.
UI를 구현 하다보면 위와 같은 요구사항을 자주 마주하게 됩니다.
그러면 우리는 간단한 코드로 이 기능을 구현할 수 있습니다.
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(...)
Text(...)
}
하지만 안드로이드 개발자라면 반드시 이 질문을 하게 됩니다.
*혹은 QA에서 잡힙니다* 😢
“텍스트가 길어서 두 줄이 될 것 같은데요? ”
물론 대부분의 기기에서는 문제가 되지 않습니다. 😃
하지만 최근 폴더블 디바이스가 늘어남에 따라 접혔을 때의 가로 크기 280dp
를 고려해야 합니다.
디자이너에게 “텍스트가 두 줄이 되면 어떻게 할까요?” 로 물어본다면 보통은 아래의 답변 중 하나가 됩니다.
- 그대로 가운데 정렬 해주세요.
- 텍스트 문구를 조금 수정할게요.
- 텍스트의 첫 번째 줄에 가운데에 정렬 시켜주세요.
그동안 우리는 이 문제를 해결하기 위해 단순한 방법을 사용 해 왔습니다.
Row {
Icon(Modifier.padding(top = 12.dp))
Text(Modifier.padding(vertical = 12.dp))
}
이 코드는 잘 동작합니다. 하지만 매우 불편합니다.
텍스트 스타일이 변경되면 어떻게 하지?
아이콘이 변경되면 어떻게 하지?
텍스트의 첫 번째 줄이 아닌 두 번째 줄에 위치해야 한다고!?
하드코딩을 사용한 코드는 버그를 발생 시키기 때문에
매번 디자인을 보고 padding
을 변경하고 싶지 않았습니다.
Alignment
Row에서는 정렬 선을 사용해 Content의 위치를 결정합니다.
따라서 단순하게 생각한다면, 정렬 선을 텍스트의 가운데에 두면 됩니다.
아이콘을 정렬하는 기준을 정의하면 다음과 같습니다.
- 텍스트가 그려지지 않았다면 ➡️ 가운데 정렬
- 텍스트가 한 줄 이라면 ➡️ 가운데 정렬
- 텍스트가 두 줄 이상이라면 ➡️ 첫 번째 줄에 정렬
이 문제를 해결하기 위해 Text에서 제공하는 TextLayoutResult를 사용 할 수 있습니다.
먼저, TextLayoutResult를 가져오기 위해 remember
를 사용합니다.
var textLayoutResult by remember { mutableStateOf<TextLayoutResult?>(null) }
Text(
onTextLayout = { textLayoutResult = it },
)
다음으로 위 기준에 따라 Alignment.Vertical을 구현하는 코드를 작성합니다.
private fun textCenterAlignment(
textLayoutResult: TextLayoutResult?,
lineCount: Int,
): Alignment.Vertical = Alignment.Vertical { size, space ->
val height = space - size
val center = (height / 2f).roundToInt() // Alignment.CenterVertically 참고
when {
textLayoutResult == null -> center // 텍스트가 그려지지 않았다면
textLayoutResult.lineCount <= 1 -> center // 텍스트가 한 줄 이라면
else -> { // 텍스트가 두 줄 이상이라면
val textHeight = textLayoutResult.size.height
val lineTop = textLayoutResult.getLineTop(lineCount)
val lineBottom = textLayoutResult.getLineBottom(lineCount)
val lineCenter = lineTop + (lineBottom - lineTop) / 2
(height - textHeight) / 2 + lineCenter.roundToInt()
}
}
}
이렇게 정의한 정렬 선을 Row의 아이콘에 배치할 수 있습니다.
var textLayoutResult by remember { mutableStateOf<TextLayoutResult?>(null) }
val alignment = remember(textLayoutResult) {
textCenterAlignment(textLayoutResult, lineCount = 0)
}
Row(
modifier = Modifier.then(modifier),
) {
Icon(
modifier = Modifier.align(alignment)
)
Text(
modifier = Modifier.align(Alignment.CenterVertically),
onTextLayout = { textLayoutResult = it },
)
}
}
지금까지 정렬 선을 이용해 아이콘을 원하는 위치에 정렬하는 방법을 알아보았습니다.
TextLayoutResult와 Alignment를 사용하면 TextView에서는 시도하지 못한 다양한 구현을 할 수 있습니다. 🎉
저희와 함께 헤이딜러 서비스를 발전 시켜나가실 분들을 기다리고 있습니다.
🎉 헤이딜러 안드로이드팀은 올해부터 Jetpack Compose와 함께합니다 🎉
감사합니다.