Text의 기준선이 필요한 이유
우리가 노트 앱을 만든다고 해보자. 노트 앱은 다양한 크기의 문자들이 들어간다. 만약 정해지지 않은 높이의 한 줄에 여러 크기의 Text가 존재한다고 할 때, 이 Text들이 만약 중앙 정렬된다면 어떻게 될까?
이를 코드로 한 번 만들어보자. MultipleTextRow는 Row의 verticalAlignment 속성을 Alignment.Center로 설정해서 두 개의 Text를 중앙 정렬한다.
@Composable
fun MultipleTextRow() {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(text = "Hello", fontSize = 16.sp)
Text(text = "Dev World", fontSize = 28.sp)
}
}
위 코드를 Preview를 통해 확인하면 [그림1]과 같아진다.
@Preview(showBackground = true)
@Composable
fun MultipleTextRowPreview() {
MultipleTextRow()
}
텍스트가 이쁘게 정렬되지 않는 것을 확인할 수 있다. 이유는 텍스트가 정렬되는 기준선이 다르기 때문이다.
그러면 이번Row의 verticalAlignment를 Alignment.Bottom으로 설정하면 두 텍스트 모두 기준선이 아래쪽이 될 것이기 때문에 이쁘게 정렬될 거 같다는 생각이 들 수 있다. 한 번 만들어보자.
@Composable
fun MultipleTextRow() {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.Bottom) {
Text(text = "Hello", fontSize = 16.sp)
Text(text = "Dev World", fontSize = 28.sp)
}
}
그러면 아래와 같이 결과가 나온다. 뭔가 어긋난 것을 볼 수 있다. 이를 만약 노트 앱에서 이런 식으로 텍스트가 나온다면 유저들의 항의를 받을 것이다.
이유가 무엇일까? 바로 텍스트의 기준선은 Text Composable 의 높이에 의해 결정되기 때문이다. 따라서 높이가 다른 두 개의 Text들은 서로 다른 기준 선을 가질 수밖에 없다.
이를 해결하기 위해 안드로이드에서는 특별한 솔루션을 제공한다. 바로 Composable 내부의 특정 값을 설정하면 텍스트들이 일정한 기준선으로 정렬되도록 만드는 것이다.
alignByBaseline 사용해 텍스트 기준선 정렬하기
Compose에서는 이를 Modifier의 속성으로 제공하며, Modifier.alignByBaseline() 으로 설정할 수 있다. 이를 설정하는 것은 매우 간단하다. Text의 modifier에 Modifier.alignByBaseline()을 넘기는 것이다.
이것이 제대로 동작하는지 알기 위해 Row의 verticalAlignment를 Alignment.CenterVertically로 바꿔서 중앙 정렬되도록 만들어 Text들이 [그림1] 처럼 중앙 정렬되게 만든다. 이후 단순히 Text의 modifier에 alignByBaseline() 속성을 아래와 같이 추가한다.
@Composable
fun MultipleTextRowAligned() {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(modifier = Modifier.alignByBaseline(), text = "Hello", fontSize = 16.sp)
Text(modifier = Modifier.alignByBaseline(), text = "Dev World", fontSize = 28.sp)
}
}
이를 Preview로 확인하면 아래 [그림3]과 같이 기준선이 정렬된 것을 볼 수 있다.
* 빨간 선은 정렬이 제대로 되는지 확인하기 위해 직접 넣은 선이다.
Preview 코드는 아래와 같다.
@Preview(showBackground = true)
@Composable
fun MultipleTextRowPreview() {
MultipleTextRowAligned()
}
이 alignByBaseline 속성은 Text나 TextField같은 Composable에서만 혹은 내부에 Text가 포함된 Composable에서만 동작한다. 예를 들어 Button 내부에 Text가 있는 경우에도 동작한다.
이유는 Text Composable이 내부에서 사용하는 BasicText Composable은 미리 정의된 Baseline을 가지고 있기 때문이다.
@Composable
fun Text(
...
) {
...
BasicText(
text,
modifier,
mergedStyle,
onTextLayout,
overflow,
softWrap,
maxLines,
)
}
그 외의 Composable에는 alignByBaseline을 사용하더라도 동작하지 않는다.
정리
- 한 줄에 있는 여러 개의 텍스트를 정렬하기 위해서는 alignByBaseline을 사용하자.
- BasicText Composable은 미리 정의된 baseline을 포함하고 있다.