Android/Jetpack Compose

분명히 텍스트 높이 지정했다니까요??? - Android Compose LineHeight Error

chattymin 2024. 7. 28. 16:22
728x90

 

 

최근 프로젝트를 진행하며 100% Compose로 Android를 구현하였다.

XML에서 하는 것 처럼 작업을 했지만, Compose에서는 다르다는 것을 깨달았던 LineHeight에 대해서 글을 써보려고 한다.

 

 

 

기존에 XML에서 코드를 작성했던 방식은 아래와 같다.

ttf혹은 otf를 추가하고, 폰트 패밀리를 만들어준다. 

 

 

 

그 후 value/appearance에서 아래와 같이 Text들의 설정을 해준다.

색상, 폰트 패밀리, 텍스트 사이즈 등을 설정하고, paddingVertical을 활용하여 LineHeight를 지정해준다.

 

 

 

이렇게 XML에서 설정해봤었고, 비슷한 방법으로 Compose에서도 이번에 설정해보고자 했다.

Compose로 구현하고자 레퍼런스로 DroidknightsAppsopt-android를 참고했다.

 

val PretendardBold = FontFamily(Font(R.font.pretendard_bold, FontWeight.Bold))
...

@Stable
class HankkiTypography internal constructor(
    h1: TextStyle,
    ...
) {
    var h1: TextStyle by mutableStateOf(h1)
        private set
    fun copy(
        h1: TextStyle = this.h1,
        ...
    ): HankkiTypography = HankkiTypography(
        h1,
        ...
    )
    fun update(other: HankkiTypography) {
        h1 = other.h1
        ...
    }
}

@Composable
fun hankkiTypography(): HankkiTypography {
    return HankkiTypography(
        h1 = TextStyle(
            fontFamily = PretendardBold,
            fontWeight = FontWeight.Bold,
            fontSize = 24.sp,
            lineHeight = 36.sp
        ),
        ...
    )
}

 

대략 이런 방식으로 코드를 작성하여 Typography를 구성했다.

 

그 외에도 CompositionLocalProvider 등을 활용해서 적용하는 과정이 있지만, 이번 글은 적용 과정이 아닌 Typograpy 자체에 대한 글이기 때문에 생략하겠다.

 

해당 방법으로 폰트를 구성을 하고 개발을 진행했다.

 

 

그런데 어느순간 UI에 이상한 부분들이 보이기 시작했다.

 

첫번째 의문점.

구현한 UI

 

Design

 

뭔가... 얇다.

 

분명히 같은 padding을 줬고, 같은 폰트를 설정했는데 뭔가 얇다.

그래서 px로 디자이너가 계산을 하지만, Android는 dp를 이용해서 화면을 나타내다보니 생기는 차이가 아닐까 생각을 했다.

 

 

 

두번째 의문점.

구현한 UI / Design

뭔가.... 좁다.

 

대학교 이름과 divider사이의 간격이 묘하게 좁다.

이 때 뭔가 문제가 있음을 깨달았다.

간격을 정확하게 줬는데 컴포넌트에서도 높이가 안맞고, UI에서도 간격이 안맞는다는 것에서 문제인식을 하게 됐다.

 

 

특히나 앞서 생각했던 px -> dp가 문제가 아니라고 확신 부분이 있었다.

만약 px -> dp가 문제라면 세로 높이 뿐만 아니라 가로에 해당하는 값도 유의미하게 차이가 보여야 한다.

하지만 세로만 문제가 생기고 있고, 가로는 디자인과 같은 형식으로 되고 있다는 것에서 확신을 얻었다.

 

 

세번째 의문점.

그러면 남은 것은 폰트의 문제다. 

그런데 난 분명히 LineHeight를 설정했고, 전부다 적용시켜뒀다.

만약 Typography가 적용되지 않았다면?

 

확실한 폰트 및 사이즈 차이

하지만 분명히 font는 적용이 되고 있었다.

Bold와 Regular를 바꾸며 테스트 해보니 확실한 차이가 보였다.

 

내가 설정한 font에는 4가지 구성요소가 있다.

fontFamily

fontWeight
fontSize 
lineHeight

이 중에서 lineHeight만 적용이 안되고 나머지 3개는 정상적으로 적용이 되고 있었다.

 

 

 

테스트를 해보자.

설정된 폰트를 이용해서 Preview를 만들고, 할당된 영역을 확인해봤다.

구현된 화면 / Design

 

요구된 높이와 실제 구현된 높이를 실제로 비교를 해보니 확연한 차이가 났다.

왜 그럴까 원인을 찾아보기로 했다.

 

 

 

왜 그런걸까? 원인을 찾아보자.

생각보다 간단한 이유였다.

 

원인을 분석하기 위해 제일 먼저 찾아본 것이 공식문서였다.

 

여기서 집중해야 하는 부분은 lineHeighStyle이다. 

그 중 alignment가 Alignment.Proportional, trim의 기본 값이 아래와 같이 Trim.Both로 되어있다.

 

그렇기 때문에 내가 설정한 값과 다른 줄간격이 나오고 있었던 것이다.

 

 

 

그래서 공통된 부분을 작성해주는 hankkiTextStyle을 이용해서 alignment와 trim을 수정해줬다.

fun hankkiTextStyle(
    fontFamily: FontFamily,
    fontWeight: FontWeight,
    fontSize: TextUnit,
    lineHeight: TextUnit,
): TextStyle = TextStyle(
    fontFamily = fontFamily,
    fontWeight = fontWeight,
    fontSize = fontSize,
    lineHeight = lineHeight,
    lineHeightStyle = LineHeightStyle(
        alignment = LineHeightStyle.Alignment.Center,
        trim = LineHeightStyle.Trim.None
    )
)

 

 

그래서 다시 레아웃을 확인해보았고, 기존에 생각하던 대로 구현된 것을 확인했다.

수정 전 / 수정 후

 

또한 문제를 인식했던 화면또한 정상적으로 수정된 것을 확인했다

 

 

물론 내가 한 방법이 100% 정석은 아니다. 공식문서를 본다면 em을 활용하라고 되어있다. 

해당 기능을 구현할 당시에는 시간적 제약이 강했고, 우선 문제 해결이 우선이었기 때문에 현재 상황에서의 최선책을 선택했다.

또한 한달 내로 릴리즈를 목표를 하고있기 때문에 현재는 이상태를 유지할 예정이다.

 

완벽한 코드도 좋지만, 기간에 맞는 코드를 작성하는 것이 더 중요한것 같다.

그래서 릴리즈를 하고 추후 스프린트에서 수정할 예정이다.

 

 

그리고... 공식문서 공부안하고 다른사람이 작성한 코드만 보고 따라 작성했던 나를 반성한다.

공식문서 봐야지 봐야지 해놓고 또 다른사람 깃허브만 봤다 하하....

 

 


2025.01.05 추가 작성글

em의 존재를 알고있으면서 그냥 넘어갔던 기억이 있어 다시 찾아봤다.

 

 

em으로 lineHeight를 설정할 경우 fontSize의 em배수만큼 lineHeight가 설정된다.

예를 들어 fonstSize가 10이고 em이 2라면 lineHeight가 20으로 설정된다.

 

 

나는 지금까지 디자이너와 협업을 하며 lineHeight에 대해서 두가지 방법으로 받아왔다.

첫 번째는 배율로 주는 경우, 두 번째는 값으로 주는 경우

 

 

배율로 준다면 em을 활용하면 되고, 값으로 준다면 sp를 활용하면 된다.

 

 

예시와 함께 알아보자.

 

@Preview(showBackground = true)
@Composable
fun SpEmTestPreview() {
    Column {
        Row {
            SpText()
            EmText()
        }

        Row {
            EmText()
            SpText()
        }
    }
}

@Composable
fun SpText() {
    Text(
        text = "SP Test",
        style = TextStyle(
            fontFamily = PretendardSemiBold,
            fontSize = 20.sp,
            lineHeight = 40.sp,
            lineHeightStyle = LineHeightStyle(
                alignment = LineHeightStyle.Alignment.Center,
                trim = LineHeightStyle.Trim.None
            )
        )
    )
}

@Composable
fun EmText() {
    Text(
        text = "EM Test",
        style = TextStyle(
            fontFamily = PretendardSemiBold,
            fontSize = 20.sp,
            lineHeight = 2.em,
            lineHeightStyle = LineHeightStyle(
                alignment = LineHeightStyle.Alignment.Center,
                trim = LineHeightStyle.Trim.None
            )
        )
    )
}

 

fontSize: 20.sp, lineHeight: 40.sp로 설정한 것 하나와

fontSize: 20.sp, lineHeight: 2.em으로 설정한 것 하나 해서

두개를 묶어 Preview를 만들어 테스트 해보았다.

 

 

Preview상에서는 SP Test와 EM Test 모두 높이가 같은 것으로 나온다.

 

 

그렇기에 어느 방법이 정답이다 라기 보다는 디자이너가 주는 방식에 맞춰 사용하는 것이 좋을 것 같다.

728x90