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 で日本語でも色々なウェイトのフォントを使いたい

Posted at

この記事は、フラー株式会社のカレンダー | 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?