1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Androidで日本語でも色々なウェイトのフォントを使いたい

1
Last updated at Posted at 2023-12-08

この記事は、フラー株式会社のカレンダー | Advent Calendar 2023 - Qiitaの9日目の記事です1

8日目はいのりこ (id:inoriko711) さんで弊社エンジニアリンググループ初、産休取得してみたでした。

はじめに

デザインの観点から、複数のLightやMediumといった色々なウエイトのフォントを使いたいということがあります。しかし、Androidの標準では日本語フォントはRegularとBoldの2種類しか表示できないです2

画像のように他のウエイトを設定しても、日本語フォントではRegularかBoldのどちらかで表示されることになります。

デフォルトでの表示

コード
val textStyle = TextStyle(
    platformStyle = PlatformTextStyle(includeFontPadding = false),
    lineHeight = 1.2.em,
)

@Preview
@Composable
fun MulchWeights1() {
    Column(modifier = Modifier.padding(8.dp)) {
        for (weight in 100..900 step 100) {
            Text(
                text = "サンプル「『』」 weight=$weight",
                style = textStyle,
                fontWeight = FontWeight(weight),
            )
        }
    }
}

このような場合は、そのウエイトに対応したフォントをGoogle Fontsなどからダウンロードして対応します。

[完]

これだけでは面白くないので、こだわりを持って複数ウエイトに対応する場合を考えます。

Androidに搭載される日本語フォントについて

Android 12以降に搭載されているフォントにはchws (Contextual Half-width Spacing) により約物が連続した時のアキを調整する機能があります3

Google FontsのNoto Sans JPではchwsの機能のないttfしかダウンロードできません。安直にこのフォントを設定した場合複数ウエイトに対応することはできても、約物が残念になってしまいます。

Google FontsのNoto Sans JPでの表示

コード
@OptIn(ExperimentalTextApi::class)
val notoSansJpGoogleFonts = FontFamily(
    (100..900 step 100).map { weight ->
        Font(
            resId = R.font.noto_sans_jp_google_fonts,
            weight = FontWeight(weight),
            variationSettings = FontVariation.Settings(FontWeight(weight), FontStyle.Normal)
        )
    }
)

val textStyle = TextStyle(
    platformStyle = PlatformTextStyle(includeFontPadding = false),
    lineHeight = 1.2.em,
)

@Preview
@Composable
fun MulchWeights2() {
    Column(modifier = Modifier.padding(8.dp)) {
        for (weight in 100..900 step 100) {
            Text(
                text = "サンプル「『』」 weight=$weight",
                style = textStyle,
                fontWeight = FontWeight(weight),
                fontFamily = notoSansJpGoogleFonts,
            )
        }
    }
}

chws機能付きのNoto Sans JPを求めて

chws機能がついたNoto Sans JPを探したところsimonsmh/notocjkというリポジトリを見つけました。このリポジトリではAndroidデバイスに含まれるパッチを加えた全てのウエイトのNoto Sans CJK / Noto Serif CJKを公開しています。

日本語のSansだけが必要なため、NotoSansCJK-VF.otf.ttc をダウンロードし、日本語の部分のotfを取得します4

これにより複数ウエイトかつ約物の間隔が綺麗な表示に対応できます。

複数ウエイトかつchwsが設定された表示

コード
@OptIn(ExperimentalTextApi::class)
val notoSansJpWithPatch = FontFamily(
    (100..900 step 100).map { weight ->
        Font(
            resId = R.font.noto_sans_jp_with_patch,
            weight = FontWeight(weight),
            variationSettings = FontVariation.Settings(FontWeight(weight), FontStyle.Normal)
        )
    }
)

val textStyle = TextStyle(
    platformStyle = PlatformTextStyle(includeFontPadding = false),
    lineHeight = 1.2.em,
)

@Preview
@Composable
fun MulchWeights3() {
    Column(modifier = Modifier.padding(8.dp)) {
        for (weight in 100..900 step 100) {
            Text(
                text = "サンプル「『』」 weight=$weight",
                style = textStyle,
                fontWeight = FontWeight(weight),
                fontFamily = notoSansJpWithPatch,
            )
        }
    }
}

バリアブルフォントを使用しているので、100より細かい単位でウエイトを変えることもできます。

細かい単位でのウエイト指定表示

コード
@OptIn(ExperimentalTextApi::class)
val notoSansJpWithPatch = FontFamily(
    (400..500 step 10).map { weight ->
        Font(
            resId = R.font.noto_sans_jp_with_patch,
            weight = FontWeight(weight),
            variationSettings = FontVariation.Settings(FontWeight(weight), FontStyle.Normal)
        )
    }
)

val textStyle = TextStyle(
    platformStyle = PlatformTextStyle(includeFontPadding = false),
    lineHeight = 1.2.em,
)

@Preview
@Composable
fun MulchWeights4() {
    Column(modifier = Modifier.padding(8.dp)) {
        for (weight in 400..500 step 10) {
            Text(
                text = "サンプル「『』」 weight=$weight",
                style = textStyle,
                fontWeight = FontWeight(weight),
                fontFamily = notoSansJpWithPatch,
            )
        }
    }
}

最後に

今回の方法では、標準のRoboto + Noto Sans JPにならず、すべてNoto Sans JPになります。その話はまたいつの日か…

  1. 本当は違うネタを書くつもりでしたが、うまくいかず急遽思いついたことを書いてます。

  2. Androidには多種多様な種類の端末があるため、例外はあります。多くの端末では、ということです。

  3. もちろん知ってましたよね? 知らないかった人は廊下に立ってください。

  4. PythonのfontToolsとか使って適当にやってください! ググればできる!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?