Jetpack Compose Text Default FontFamily(기본 폰트) 설정하기

2024. 4. 29. 19:44·Jetpack Compose

FontFamily

커스텀 폰트를 사용하려면 FontFamily를 만들어 Text를 사용할 때마다 fontFamily 속성을 설정해 주어야 하는 번거로움이 있다. 이를 해결하기 위해 CompositionLocalProvider를 사용해 Default FontFamily를 설정하여 Text 사용 시 별도로 fontFamily를 설정하지 않아도 되는 방법을 소개한다.

 

CompositionLocalProvider

@Composable
@OptIn(InternalComposeApi::class)
fun CompositionLocalProvider(value: ProvidedValue<*>, content: @Composable () -> Unit) {
    currentComposer.startProvider(value)
    content()
    currentComposer.endProvider()
}
"일반적으로 Compose에서 데이터는 각 구성 가능한 함수의 매개변수로 UI 트리를 통해 아래로 흐릅니다. 따라서 컴포저블의 종속 항목이 명시적으로 됩니다. 그러나 이 방법은 색상이나 유형 스타일과 같이 매우 자주 널리 사용되는 데이터의 경우에는 번거로울 수 있습니다."

라고 설명한다. 요약하자면 자주 사용하는 데이터는 매번 명시적으로 컴포저블에 전달하기 번거롭기 때문에 CompositionLocalProvider를 사용해 암시적으로 사용할 수 있다라는 말이다.

 

MaterialTheme

@Composable
fun MaterialTheme(
    colorScheme: ColorScheme = MaterialTheme.colorScheme,
    shapes: Shapes = MaterialTheme.shapes,
    typography: Typography = MaterialTheme.typography,
    content: @Composable () -> Unit
) {
    val rippleIndication = androidx.compose.material.ripple.rememberRipple()
    val selectionColors = rememberTextSelectionColors(colorScheme)
    CompositionLocalProvider(
        LocalColorScheme provides colorScheme,
        LocalIndication provides rippleIndication,
        androidx.compose.material.ripple.LocalRippleTheme provides MaterialRippleTheme,
        LocalShapes provides shapes,
        LocalTextSelectionColors provides selectionColors,
        LocalTypography provides typography,
    ) {
        ProvideTextStyle(value = typography.bodyLarge, content = content)
    }
}

CompositionLocalProvider를 사용하는 널리 알려진 예시로 MaterialTheme가 있다.

 

MaterialTheme는 색상, 서체, 도형을 설정 후 하위 부분에서 세 가지의 인스턴트를 제공하는 객체로 MaterialTheme 코드를 확인해보면 CompositionLocalProvider를 사용해 colorScheme, rippleIndication, shapes, typograpy 등 자주 사용되는 데이터를 설정하고 있다.

 

따라서 fontFamily도 자주 사용한다면 같은 방법으로 설정할 수 있는 것이다.

 

ProvideTextStyle

@Composable
fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit) {
    val mergedStyle = LocalTextStyle.current.merge(value)
    CompositionLocalProvider(LocalTextStyle provides mergedStyle, content = content)
}

직접 CompositionLocalProvider를 사용해 LocalTextStyle을 설정해도 되지만 인라인 함수가 아닌 textStyle을 설정하는 함수가 존재한다. 따라서 이 함수를 사용해서 LocalTextStyle을 설정하는 방법을 설명한다.

 

설정 방법

// Theme.kt
@Composable
fun AppTheme(
    content: @Composable () -> Unit
) {
    MaterialTheme(
        typography = typography // 하단 설명 참고
    ) {
        ProvideTextStyle(
            value = TextStyle(
                fontFamily = pretendard
            )
        ) {
            content()
        }
    }
}

// MainActivity.kt
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        enableEdgeToEdge()

        setContent {
            ReReminderTheme { MainNavigation() }
        }
    }
}

Theme.kt에서 theme를 설정할 때 ProvideTextStyle 함수를 호출해 기본 fontFamily를 설정해준다. pretendard는 예시일 뿐 본인이 사용할 fontFamily를 입력해주면 된다. 이 후 메인 액티비티에서 theme를 적용시킨다. 

 

하지만 Button이나 AppBar 등 일부 컴포넌트 내부에서 Text를 사용할 시 fontFamily가 적용이 안되는 경우가 있다. 그 이유는 어떤 컴포넌트 내부에서는 ProvideTextStyle 함수를 새롭게 호출해 fontFamily를 설정하는데 이때 MaterialTheme.typography의 값을 사용해 설정하기 때문이다.

 

이를 해결하는 방법은 MaterialTheme.typography에도 fontFamily를 적용시키면 된다. 이 때 약간의 문제가 있는데 Material3의 Typography 자체는 참고해서 사용할 수 있지만 내부에서 값을 설정하는 토큰은 internal로 되어있어 참고해서 사용할 수 없다. 그래서 토큰 값을 직접 베껴서 똑같이 설정했으므로 알아서 수정해서 사용하도록 한다.

val DefaultTextStyle = TextStyle.Default.copy(
    fontFamily = pretendard,
    fontWeight = FontWeight.Normal,
    lineHeightStyle = LineHeightStyle(
        alignment = LineHeightStyle.Alignment.Center,
        trim = LineHeightStyle.Trim.None
    )
)

val typography = Typography(
    bodyLarge = DefaultTextStyle.copy(
        fontSize = 16.sp,
        lineHeight = 24.sp,
        letterSpacing = 0.5.sp
    ),
    bodyMedium = DefaultTextStyle.copy(
        fontSize = 14.sp,
        lineHeight = 20.sp,
        letterSpacing = 0.2.sp
    ),
    bodySmall = DefaultTextStyle.copy(
        fontSize = 12.sp,
        lineHeight = 16.sp,
        letterSpacing = 0.4.sp
    ),
    displayLarge = DefaultTextStyle.copy(
        fontSize = 57.sp,
        lineHeight = 64.sp,
        letterSpacing = (-0.2).sp
    ),
    displayMedium = DefaultTextStyle.copy(
        fontSize = 45.sp,
        lineHeight = 52.sp,
        letterSpacing = 0.0.sp
    ),
    displaySmall = DefaultTextStyle.copy(
        fontSize = 36.sp,
        lineHeight = 44.sp,
        letterSpacing = 0.0.sp
    ),
    headlineLarge = DefaultTextStyle.copy(
        fontSize = 32.sp,
        lineHeight = 40.sp,
        letterSpacing = 0.0.sp
    ),
    headlineMedium = DefaultTextStyle.copy(
        fontSize = 24.sp,
        lineHeight = 32.sp,
        letterSpacing = 0.0.sp
    ),
    headlineSmall = DefaultTextStyle.copy(
        fontSize = 36.sp,
        lineHeight = 44.sp,
        letterSpacing = 0.0.sp
    ),
    labelLarge = DefaultTextStyle.copy(
        fontWeight = FontWeight.Medium,
        fontSize = 14.sp,
        lineHeight = 20.sp,
        letterSpacing = 0.1.sp
    ),
    labelMedium = DefaultTextStyle.copy(
        fontWeight = FontWeight.Medium,
        fontSize = 12.sp,
        lineHeight = 16.sp,
        letterSpacing = 0.5.sp
    ),
    labelSmall = DefaultTextStyle.copy(
        fontWeight = FontWeight.Medium,
        fontSize = 11.sp,
        lineHeight = 16.sp,
        letterSpacing = 0.5.sp
    ),
    titleLarge = DefaultTextStyle.copy(
        fontWeight = FontWeight.Medium,
        fontSize = 22.sp,
        lineHeight = 28.sp,
        letterSpacing = 0.0.sp
    ),
    titleMedium = DefaultTextStyle.copy(
        fontSize = 16.sp,
        lineHeight = 24.sp,
        letterSpacing = 0.2.sp
    ),
    titleSmall = DefaultTextStyle.copy(
        fontWeight = FontWeight.Medium,
        fontSize = 14.sp,
        lineHeight = 20.sp,
        letterSpacing = 0.1.sp
    )
)

* 이렇게 해도 fontFamily가 적용되지 않는 BasicTextField 같은 컴포넌트가 있는데 내부 코드를 확인해보면 직접 입력된 textStyle이 없다면 컨스트럭터를 통해 fontFamily를 null로 설정하기 때문이다. 따라서 위의 코드를 사용했을 때 적용되지 않는 컴포넌트는 어쩔 수 없이 내부 코드를 확인 후 textStyle에 fontFamily를 직접 설정해 주어야 한다.

 

Reference

https://developer.android.com/develop/ui/compose/compositionlocal?hl=ko

 

CompositionLocal을 사용한 로컬 범위 지정 데이터  |  Jetpack Compose  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. CompositionLocal을 사용한 로컬 범위 지정 데이터 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Composition

developer.android.com

'Jetpack Compose' 카테고리의 다른 글
  • Jetpack Compose로 Calendar 만들기
  • Jetpack Compose Text Width(텍스트 너비) 측정하기
  • Jetpack Compose로 Drag and Drop(드래그해서 재정렬) 기능 만들기
  • Jetpack Compose 사용하기
브애애앳
브애애앳
  • 브애애앳
    디벨로퍼즐
    브애애앳
  • 전체
    오늘
    어제
    • 분류 전체보기 (24) N
      • Android App (3) N
      • Android Studio (2)
      • Figma (0)
      • Jetpack Compose (15)
      • Kotlin (3)
      • Tistory (1)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.0
브애애앳
Jetpack Compose Text Default FontFamily(기본 폰트) 설정하기
상단으로

티스토리툴바