フォントを操作する

このページでは、Compose アプリでフォントを設定する方法について説明します。

フォントを設定する

Text には、コンポーザブルで使用されるフォントを設定するための fontFamily パラメータを指定できます。デフォルトでは、Serif、Sans Serif、Monospace、Cursive のフォント ファミリー が 含まれています

@Composable
fun DifferentFonts() {
    Column {
        Text("Hello World", fontFamily = FontFamily.Serif)
        Text("Hello World", fontFamily = FontFamily.SansSerif)
    }
}

「

fontFamily 属性を使用して、res/font フォルダで定義されているカスタムのフォントと書体を操作できます。

開発環境の res > font フォルダの図

この例では、これらのフォント ファイルに基づいて Font 関数を使用して fontFamily を定義する方法を示します。

val firaSansFamily = FontFamily(
    Font(R.font.firasans_light, FontWeight.Light),
    Font(R.font.firasans_regular, FontWeight.Normal),
    Font(R.font.firasans_italic, FontWeight.Normal, FontStyle.Italic),
    Font(R.font.firasans_medium, FontWeight.Medium),
    Font(R.font.firasans_bold, FontWeight.Bold)
)

この fontFamilyText コンポーザブルに渡すことができます。fontFamily には、異なる太さを含めることが可能です。その場合は、次のように手動で fontWeight を設定して、テキストに適した太さを選択します。

Column {
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Light)
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Normal)
    Text(
        text = "text",
        fontFamily = firaSansFamily,
        fontWeight = FontWeight.Normal,
        fontStyle = FontStyle.Italic
    )
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Medium)
    Text(text = "text", fontFamily = firaSansFamily, fontWeight = FontWeight.Bold)
}

「

アプリ全体のタイポグラフィを設定する方法については、Compose のカスタム デザイン システムをご覧ください。

ダウンロード可能なフォント

Compose 1.2.0 以降では、Compose アプリでダウンロード可能なフォント API を使用して Google fonts を非同期でダウンロードし、アプリで使用することができます。

カスタム プロバイダが提供するダウンロード可能なフォントは、現時点ではサポートされていません。

プログラムを介してダウンロード可能なフォントを使用する

アプリ内からプログラムを介してフォントをダウンロードするには、次の手順を行います。

  1. 依存関係を追加します。

    Groovy

    dependencies {
        ...
        implementation "androidx.compose.ui:ui-text-google-fonts:1.11.3"
    }

    Kotlin

    dependencies {
        ...
        implementation("androidx.compose.ui:ui-text-google-fonts:1.11.3")
    }
  2. Google Fonts の認証情報で GoogleFont.Provider を初期化します:
    val provider = GoogleFont.Provider(
        providerAuthority = "com.google.android.gms.fonts",
        providerPackage = "com.google.android.gms",
        certificates = R.array.com_google_android_gms_fonts_certs
    )
    プロバイダが受け取るパラメータは次のとおりです。
  3. FontFamily を定義します。
    // ...
     import androidx.compose.ui.text.googlefonts.GoogleFont
     import androidx.compose.ui.text.font.FontFamily
     import androidx.compose.ui.text.googlefonts.Font
     // ...
    
    val fontName = GoogleFont("Lobster Two")
    
    val fontFamily = FontFamily(
        Font(googleFont = fontName, fontProvider = provider)
    )
    フォントの他のパラメータをクエリすることもできます。たとえば、weight と style には FontWeightFontStyle をそれぞれ使用します。
    // ...
     import androidx.compose.ui.text.googlefonts.GoogleFont
     import androidx.compose.ui.text.font.FontFamily
     import androidx.compose.ui.text.googlefonts.Font
     // ...
    
    val fontName = GoogleFont("Lobster Two")
    
    val fontFamily = FontFamily(
        Font(
            googleFont = fontName,
            fontProvider = provider,
            weight = FontWeight.Bold,
            style = FontStyle.Italic
        )
    )
  4. コンポーズ可能な Text 関数で使用できるように FontFamily を 設定します。

Text(
    fontFamily = fontFamily, text = "Hello World!"
)

`FontFamily` を使用する タイポグラフィを定義することもできます。

val MyTypography = Typography(
    bodyMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp/*...*/
    ),
    bodyLarge = TextStyle(
        fontFamily = fontFamily,
        fontWeight = FontWeight.Bold,
        letterSpacing = 2.sp,
        /*...*/
    ),
    headlineMedium = TextStyle(
        fontFamily = fontFamily, fontWeight = FontWeight.SemiBold/*...*/
    ),
    /*...*/
)

次に、タイポグラフィをアプリのテーマに設定します。

MyAppTheme(
    typography = MyTypography
)/*...*/

Compose でダウンロード可能なフォントを マテリアル 3と一緒に実装するアプリの例については、 Jetchatサンプルアプリをご覧ください。

代替フォントを追加する

フォントが適切にダウンロードされなかった場合に備えて、フォントの代替チェーンを指定できます。たとえば、ダウンロード可能なフォントを次のように定義したとします。

// ...
 import androidx.compose.ui.text.googlefonts.Font
 // ...

val fontName = GoogleFont("Lobster Two")

val fontFamily = FontFamily(
    Font(googleFont = fontName, fontProvider = provider),
    Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold)
)

両方のウェイトのデフォルト フォントを次のように定義できます。

// ...
 import androidx.compose.ui.text.font.Font
 import androidx.compose.ui.text.googlefonts.Font
 // ...

val fontName = GoogleFont("Lobster Two")

val fontFamily = FontFamily(
    Font(googleFont = fontName, fontProvider = provider),
    Font(resId = R.font.my_font_regular),
    Font(googleFont = fontName, fontProvider = provider, weight = FontWeight.Bold),
    Font(resId = R.font.my_font_regular_bold, weight = FontWeight.Bold)
)

正しいインポートを追加していることを確認してください。

このように FontFamily を定義すると、2 つのチェーン(ウェイトごとに 1 つ)を含む FontFamily が作成されます。読み込みメカニズムでは、まずオンライン フォントを解決し、次にローカルの R.font リソース フォルダにあるフォントを解決しようとします。

実装をデバッグする

フォントが正しくダウンロードされていることを確認するには、デバッグ コルーチン ハンドラを定義します。ハンドルを使用すると、フォントが非同期でロードされなかった場合に実行する動作を指定できます。

まず、 CoroutineExceptionHandler を作成します。

val handler = CoroutineExceptionHandler { _, throwable ->
    // process the Throwable
    Log.e(TAG, "There has been an issue: ", throwable)
}

それを createFontFamilyResolver メソッドに渡して、リゾルバが新しいハンドラを使用できるようにします。

CompositionLocalProvider(
    LocalFontFamilyResolver provides createFontFamilyResolver(LocalContext.current, handler)
) {
    Column {
        Text(
            text = "Hello World!", style = MaterialTheme.typography.bodyMedium
        )
    }
}

プロバイダの isAvailableOnDevice API を使用して、プロバイダが利用可能であり、証明書が 正しく構成されているかどうかをテストすることもできます。これを行うには、プロバイダが正しく構成されていない場合に false を返す isAvailableOnDevice メソッドを呼び出します。

val context = LocalContext.current
LaunchedEffect(Unit) {
    if (provider.isAvailableOnDevice(context)) {
        Log.d(TAG, "Success!")
    }
}

注意点

Google Fonts では、Android で新しいフォントを利用できるようになるまでに数か月かかります。 フォントが fonts.google.com に追加されてから、 ダウンロード可能なフォント API(ビューシステムまたは Compose)で利用できるようになるまでに時間的なずれがあります。新しく 追加されたフォントがアプリで読み込まれず、 IllegalStateExceptionが発生する可能性があります。 デベロッパーがこのエラーを他の種類のフォント読み込みエラーと区別できるように、 Compose の例外に説明メッセージを追加しました。変更点については こちらをご覧ください。 問題が見つかった場合は、公開バグトラッカー を使用して報告してください

可変フォントを使用する

可変フォントは、1 つのフォント ファイルにさまざまなスタイルを含めることができるフォント形式です。可変フォントを使用すると、軸(パラメータ)を変更して好みのスタイルを生成できます。これらの軸は、太さ、幅、傾斜、斜体などの標準軸と、可変フォントごとに異なるカスタム軸があります。

軸の値が異なる同じバリアブル フォントの 5 つの構成。
図 1.同じ可変フォントを使用し、軸の値をカスタマイズしたテキスト。

通常のフォント ファイルの代わりに可変フォントを使用すると、複数のフォント ファイルではなく 1 つのフォント ファイルのみを使用できます。

可変フォントの詳細については、Google Fonts Knowledge、利用可能な可変フォントのカタログ全体、各 フォントでサポートされている軸のをご覧ください。

このドキュメントでは、Compose アプリで可変フォントを実装する方法について説明します。

可変フォントを読み込む

  1. 使用する可変フォント(例: Roboto Flex)をダウンロードし、アプリのapp/res/fontフォルダに配置します。ttf ファイルがフォントの 可変フォント バージョンであることを確認してください。また、フォント ファイル名は すべて小文字で、特殊文字を含まないようにしてください。

  2. 可変フォントを読み込むには、res/font/ ディレクトリに配置したフォントを使用して FontFamily を定義します。

    // In Typography.kt
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily =
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(950),
                    FontVariation.width(30f),
                    FontVariation.slant(-6f),
                )
            )
        )

    FontVariation API を使用すると、 太さ傾斜などの標準フォント軸を構成できます。これらは、任意の可変フォントで使用できる標準軸です。フォントを使用する場所に基づいて、フォントのさまざまな構成を作成できます。

  3. 可変フォントは Android バージョン O 以降でのみ使用できるため、ガードレールを追加して適切なフォールバックを構成します。

    // In Typography.kt
    val default = FontFamily(
        /*
        * This can be any font that makes sense
        */
        Font(
            R.font.robotoflex_static_regular
        )
    )
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(950),
                    FontVariation.width(30f),
                    FontVariation.slant(-6f),
                )
            )
        )
    } else {
        default
    }

  4. 再利用しやすいように設定を定数セットに抽出し、フォント設定をこれらの定数に置き換えます。

    // VariableFontDimension.kt
    object DisplayLargeVFConfig {
        const val WEIGHT = 950
        const val WIDTH = 30f
        const val SLANT = -6f
        const val ASCENDER_HEIGHT = 800f
        const val COUNTER_WIDTH = 500
    }
    
    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(DisplayLargeVFConfig.WEIGHT),
                    FontVariation.width(DisplayLargeVFConfig.WIDTH),
                    FontVariation.slant(DisplayLargeVFConfig.SLANT),
                )
            )
        )
    } else {
        default
    }

  5. マテリアル デザイン 3 の タイポグラフィ を使用するように FontFamily を構成します。

    // Type.kt
    val Typography = Typography(
        displayLarge = TextStyle(
            fontFamily = displayLargeFontFamily,
            fontSize = 50.sp,
            lineHeight = 64.sp,
            letterSpacing = 0.sp,
            /***/
        )
    )

    このサンプルでは、displayLarge マテリアル 3 タイポグラフィを使用します。これは、デフォルトのフォント設定と推奨される用途が異なります 。たとえば、画面上で最も大きなテキストであるため、短くて重要なテキストには displayLarge を使用する必要があります。

    マテリアル 3 では、TextStylefontFamily のデフォルト値を変更して、タイポグラフィをカスタマイズできます。上記のスニペットでは、各フォント ファミリーのフォント設定をカスタマイズするように TextStyle のインスタンスを構成しています。

  6. タイポグラフィを定義したので、色とタイポグラフィと同様に、これを M3 MaterialTheme に渡します。

    MaterialTheme(
        colorScheme = MaterialTheme.colorScheme,
        typography = Typography,
        content = content
    )

  7. 最後に、Text コンポーザブルを使用して、スタイルを定義済みのタイポグラフィ スタイル(MaterialTheme.typography.displayLarge)のいずれかに指定します。

    @Composable
    @Preview
    fun CardDetails() {
        MyCustomTheme {
            Card(
                shape = RoundedCornerShape(8.dp),
                elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
            ) {
                Column(
                    modifier = Modifier.padding(16.dp)
                ) {
                    Text(
                        text = "Compose",
                        style = MaterialTheme.typography.displayLarge,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 1
                    )
                    Text(
                        text = "Beautiful UIs on Android",
                        style = MaterialTheme.typography.headlineMedium,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 2
                    )
                    Text(
                        text = "Jetpack Compose is Android’s recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.",
                        style = MaterialTheme.typography.bodyLarge,
                        modifier = Modifier.padding(bottom = 8.dp),
                        maxLines = 3
                    )
                }
            }
        }
    }

    Text コンポーザブルは、マテリアル テーマのスタイルで構成され、異なる可変フォント構成が含まれています。 MaterialTheme.typography を使用すると、M3 MaterialTheme コンポーザブルに提供されるタイポグラフィを取得できます。

3 つの異なるテキスト。それぞれ異なるフォント設定を示しています。
図 2.3 つの異なる構成で適用された可変フォント。

カスタム軸を使用する

フォントにはカスタム軸を設定することもできます。これらはフォント ファイル自体で定義されます。 たとえば、Roboto Flex フォントには、アセンダーの高さ("YTAS")軸と、小文字のアセンダーの高さを調整する 各文字の幅を調整するカウンター幅("XTRA") 軸があります。

これらの軸の値は、FontVariation 設定で変更できます。

フォントに構成できるカスタム軸の詳細については、 各フォントでサポートされている軸の表をご覧ください。

  1. カスタム軸を使用するには、カスタムの ascenderHeight 軸と counterWidth 軸の関数を定義します。

    fun ascenderHeight(ascenderHeight: Float): FontVariation.Setting {
        require(ascenderHeight in 649f..854f) { "'Ascender Height' must be in 649f..854f" }
        return FontVariation.Setting("YTAS", ascenderHeight)
    }
    
    fun counterWidth(counterWidth: Int): FontVariation.Setting {
        require(counterWidth in 323..603) { "'Counter width' must be in 323..603" }
        return FontVariation.Setting("XTRA", counterWidth.toFloat())
    }

    これらの関数は次の処理を行います。

  2. フォント構成で軸を使用して、読み込まれる各 Font に追加のパラメータを渡します。

    @OptIn(ExperimentalTextApi::class)
    val displayLargeFontFamily = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        FontFamily(
            Font(
                R.font.robotoflex_variable,
                variationSettings = FontVariation.Settings(
                    FontVariation.weight(DisplayLargeVFConfig.WEIGHT),
                    FontVariation.width(DisplayLargeVFConfig.WIDTH),
                    FontVariation.slant(DisplayLargeVFConfig.SLANT),
                    ascenderHeight(DisplayLargeVFConfig.ASCENDER_HEIGHT),
                    counterWidth(DisplayLargeVFConfig.COUNTER_WIDTH)
                )
            )
        )
    } else {
        default
    }

    小文字のアセンダーの高さが増加し、他のテキストの幅が広くなっていることに注意してください。

バリアブル フォントのさまざまな構成を示す 3 つの異なるテキスト。カスタム軸が設定されており、小文字のアセンダーが高く、以前よりも幅が広いものもあります。
図 3.可変フォントに設定されたカスタム軸を示すテキスト。

参考情報

詳細については、可変フォントに関する次のブログ投稿をご覧ください。