[読書会]カスタムフォントの利用

AndroidとiOSは高品質のシステムフォントを提供しているが、デザイナーはカスタムフォントのサポートを求めています。デザイナーによる特注フォントを持っているかもしれないし、Google Fontsからフォントをダウンロードしたかもしれません。

書体とは、あるレタリングのスタイルを構成するグリフや図形の集まりです。フォントとは、与えられたウェイトやバリエーションでその書体を表現したものです。フォントとは、あるウェイトやバリエーションでその書体を表現したものです。 Robotoは書体であり、Roboto Boldはフォントです。

Flutterでは、アプリ全体または個々のウィジェットにカスタムフォントを適用できます。

1.フォントの選択

フォントの選択は好み以上のものであるべきです。どのファイル形式がFlutterで動作するのか、フォントがデザインオプションやアプリのパフォーマンスにどのような影響を与える可能性があるのかを考えてみましょう。

(1)サポートされているフォントフォーマットの選択

Flutterは以下のフォントフォーマットに対応しています。

  • OpenType font collections: .ttc
  • TrueType fonts: .ttf
  • OpenType fonts: .otf

Flutterはデスクトッププラットフォーム上では、Web Open Font Format.woff および .woff2 のフォントをサポートしていません。

(2)特定の利点に応じたフォントの選択

フォント・ファイル・タイプが何であるか、あるいはどちらの方が使用する容量が少ないかについて、同意している情報源はほとんどありません。フォントファイルタイプの主な違いは、ファイル内のグリフをどのようにエンコードするかということです。ほとんどのTrueTypeフォントファイルとOpenTypeフォントファイルは、時代とともにフォーマットとフォントが改良されるにつれて、互いに借用し合ったため、似たような機能を持っています。

どのフォントを使うべきかは、以下の点を考慮する必要があります。

  • アプリのフォントにはどれくらいのバリエーションが必要ですか?
  • アプリで使用できるフォントのファイルサイズは?
  • アプリでサポートする必要のある言語はいくつありますか?

フォントファイルごとに複数のウェイトやスタイル、可変フォント機能、複数のウェイトに対応する複数のフォントファイルの有無、フォントごとに複数の幅など、指定したフォントがどのようなオプションを提供しているかを調べます。

アプリのデザインニーズに合った書体やフォントファミリーを選びましょう。

1,000以上のオープンソースフォントファミリーに直接アクセスする方法は、google_fontsパッケージをチェックして下さい。

参考ビデオ:Package of the Week 「Google_fonts」(https://youtu.be/8Vzv2CdbEY0)

2.フォントファイルのダウンロード

フォントは、Flutterプロジェクトにフォントファイルをダウンロードすることで使用できます。

(ダウンロードしたフォントファイルの格納場所(例))Flutterプロジェクトフォルダ直下の fonts フォルダ(※assets フォルダも一般的)
custom_fonts/
      |- fonts/
            |- Raleway-Regular.ttf
            |- Raleway-Italic.ttf
            |- RobotoMono-Regular.ttf
            |- RobotoMono-Bold.ttf

3.pubspec.yaml へのフォント宣言

フォントをダウンロードしたら、pubspec.yaml ファイルにフォント定義を含めます。このフォント定義では、アプリ内で指定されたウェイトやスタイルをレンダリングするために、どのフォントファイルを使用するかも指定します。

(1)pubspec.yaml 中のフォント定義

フォント定義の宣言(例):
  fonts:
    - family: Raleway
      fonts:
        - asset: fonts/Raleway-Regular.ttf
        - asset: fonts/Raleway-Italic.ttf //←指定されている
          style: italic //←上記のItalicの方を指定
    - family: RobotoMono
      fonts:
        - asset: fonts/RobotoMono-Regular.ttf
        - asset: fonts/RobotoMono-Bold.ttf
          weight: 700

上記定義後、以下の様に、 TextStyle fontFamily を指定してフォントを使用できます。

上記設定済の Releway フォントの使用(例):
Text(
  'Hello, Flutter!',
  style: TextStyle(
    //上記指定済みの ファミリー名 を使用
    fontFamily: 'Raleway',
    fontSize: 24,
  ),
);

(2)各フォントのフォントファイルのインクルード

書体によってフォントファイルの実装方法は異なります。さまざまなウェイトやスタイルの書体が必要な場合は、その種類を表すフォントファイルを選んでインポートします。

複数のフォントや可変フォント機能を含まないフォントファイルをインポートする場合、styleweightプロパティを使って表示方法を調整しないで下さい。通常のフォントファイルでこれらのプロパティを使用すると、Flutterは見た目をシミュレートしようとします。視覚的な結果は、正しいフォントファイルを使うのとはまったく違って見えるでしょう。

(3)フォントファイルでのスタイルと太さの設定

どのフォントファイルがフォントのstyleweightを表すかを宣言すると、styleweightのプロパティを適用することができます。

(3-1)フォントの太さの設定

weightプロパティは、ファイル内のアウトラインの太さ100の整数倍(100~900)指定します。
これらの値はFontWeightに対応しており、TextStyleオブジェクトのfontWeightプロパティで使用することができます。

フォント定義の宣言(例)※再掲載:
  fonts:
    - family: Raleway
      fonts:
        - asset: fonts/Raleway-Regular.ttf
        - asset: fonts/Raleway-Italic.ttf //←指定されている
          style: italic //←上記のItalicの方を指定
    - family: RobotoMono
      fonts:
        - asset: fonts/RobotoMono-Regular.ttf
        - asset: fonts/RobotoMono-Bold.ttf
          weight: 700

このガイドで示した pubspec.yaml では、fonts.family として、RobotoMono-Boldweight: 700)を定義しましたので、もし、このRobotoMono-Boldフォントを使用するには、TextStyleウィジェットでfontWeight に、FontWeight.w700 と設定します。

上記設定済の RobotoMono フォントの使用(例):
Text(
  'Bold Text',
  style: TextStyle(
    fontFamily: 'RobotoMono',        // 定義したファミリー名を使用
    fontWeight: FontWeight.w700,     // 太字(700)を適用
  ),
);

アプリにRobotoMono-Boldを追加していなかった場合、Flutterはフォントを太く見せようとします。 その場合、テキストは多少暗く見えるかもしれません。

weightプロパティを使ってフォントの太さを上書きすることはできません。RobotoMono-Boldに700以外のウェイトを設定することはできません。TextStyle(fontFamily:’RobotoMono’, fontWeight: FontWeight.w900)を設定しても、表示されるフォントはRobotoMono-Boldのように太く表示されます。

(3-2)フォントのスタイルの設定

style プロパティは、フォントファイル内のグリフをイタリック体として表示するか、ノーマル体として表示するかを指定します。これらの値はFontStyleに対応する。これらのスタイルは、TextStyleオブジェクトのfontStyleプロパティで使用できます。

フォント定義の宣言(例)※再掲載:
  fonts:
    - family: Raleway
      fonts:
        - asset: fonts/Raleway-Regular.ttf
        - asset: fonts/Raleway-Italic.ttf //←指定されている
          style: italic //←上記のItalicの方を指定
    - family: RobotoMono
      fonts:
        - asset: fonts/RobotoMono-Regular.ttf
        - asset: fonts/RobotoMono-Bold.ttf
          weight: 700

このガイドに示されている pubspec.yaml では、Raleway-Italicイタリック体であると定義されています。
アプリに追加したRaleway-Italicフォントを使用するには、styleTextStyle(fontStyle::FontStyle.italic)を設定します。

上記設定済の Raleway フォントの使用(例):
Text(
  'This text is italic',
  style: TextStyle(
    fontFamily: 'Raleway',        // 定義したファミリー名を使用
    fontStyle: FontStyle.italic,  // Raleway-Italic.ttf が適用される
  ),
);

(注意点)イタリック体と標準体のフォント設定

① 異なるスタイル表示時は、別フォントファイルを pubspec.yaml に定義し使用用様に設定する必要がある:

説明文では、
TextStyle(fontFamily: ‘Raleway’, fontStyle: FontStyle.normal)
の設定についても触れていますが、これは少し特殊なケースです。

例えば、pubspec.yaml で Raleway-Italic.ttf を定義した場合、Raleway-Italic.ttf は常にイタリック体として認識されます。
TextStyle で fontStyle: FontStyle.normal を指定しても、そのフォントファイル自体がイタリック体なので、結果としてイタリック体で表示されることになります。

このことから、フォントファイルのスタイルを変更することはできず、ファイルに含まれるグリフ(文字形状)のスタイルはそのまま適用されることになります。異なるスタイルを表示したい場合は、別のフォントファイルを pubspec.yaml に定義し、そのファイルを使うように設定する必要があります。

② フォントファイルを pubspec.yaml に定義・設定していない場合、あくまでも標準体のフォントを使用する:

また、「Raleway-Italic.ttf が定義されていない場合、Flutter がイタリック体をシミュレートする」とも、述べられています。

これは、FontStyle.italic を指定しても対応するイタリック体のフォントファイルがない場合、Flutter は標準体のフォントを右に傾けて表示し、イタリック体のように見せようとする挙動です。
しかし、このシミュレーションによる表示は本来のイタリック体とは異なり、文字の線の太さや形状が理想的でないことが多いため、視覚的な違いが生じます。

4.デフォルトフォントの設定

ここでは、Flutter アプリケーション全体にデフォルトのフォントを適用する方法について解説しています。具体的には、ThemeDatafontFamily プロパティを設定し、MaterialApp のテーマとして適用することで、アプリ内の全てのテキストに指定したフォントを反映させる方法を説明しています。

(1)デフォルトフォントの設定とは?

通常、Flutter アプリケーションでは、テキストに適用するフォントを個別の Text ウィジェットごとに設定できます。しかし、アプリケーション全体に統一されたフォントを適用したい場合、デフォルトフォントを設定すると便利です。

これを実現するには、ThemeData の fontFamily プロパティを設定し、そのテーマを MaterialApp の theme プロパティに適用します。

(2)fontFamily プロパティの設定方法

以下のように、MaterialApp ウィジェット内の theme プロパティに ThemeData(fontFamily: ‘Raleway’) を設定します。

fontFamily プロパティの設定により、デフォルトフォントを Raleway とする例:
return MaterialApp(
  title: 'Custom Fonts',
  theme: ThemeData(
    //pubspec.yaml で定義したファミリー名を設定
    fontFamily: 'Raleway',
  ),
  home: const MyHomePage(),
);

(3)設定の結果と効果

この設定を行うと、アプリケーション全体のデフォルトのフォントが Raleway になります。つまり、各 Text ウィジェットの style プロパティで個別に fontFamily を指定しなくても、アプリの全テキストが自動的に Raleway フォントで表示されるようになります。

例えば、以下の Text ウィジェットは fontFamily を未指定ですが、ThemeData で設定したデフォルトフォントが適用されます。

デフォルトフォント設定による効果:
Text(
  'This text uses the default Raleway font.',
  //このText ウィジェットは fontFamily を未指定ですが、
  //ThemeData で設定した デフォルトの Raleway が適用されます
  style: Theme.of(context).textTheme.bodyMedium,
);

もし、fontFamily を変更したい場合は、ThemeData の fontFamily プロパティを更新するだけで済みます。個々の Text ウィジェットでスタイルを設定し直す必要がありません。

テーマについて詳しくは、テーマを使って色とフォントスタイルを共有するレシピをご覧下さい。

5.特定のウィジェットへのフォントの設定

ここでは、特定のウィジェットにフォントを適用する方法について解説しています。特に、Text ウィジェットに TextStyle を設定する際に、fontFamily を指定する方法を説明しています。

(1)特定のウィジェットにフォントを適用する方法

通常、Flutter ではアプリ全体のデフォルトフォントを ThemeData の fontFamily プロパティで設定できますが、特定のウィジェットだけに別のフォントを適用したい場合もあるかと思います。

その場合、各ウィジェットに TextStyle オブジェクトを設定し、fontFamily を指定します。TextStyle の fontFamily プロパティに指定するフォント名は、pubspec.yaml で定義された family 名と一致している必要があります。

特定の Text ウィジェットに RobotoMono フォントを適用する例:
Text(
  'Roboto Mono sample',
  style: TextStyle(
    fontFamily: 'RobotoMono',  //pubspec.yaml で定義したファミリー名
  ),
);

上記は、pubspec.yaml で RobotoMono フォントファミリーを定義した場合に使用できます。style プロパティに TextStyle(fontFamily: ‘RobotoMono’) を指定することで、その Text ウィジェットに RobotoMono フォントが適用されます。

(2)重要な注意点

フォントファイルが存在しない場合、
① TextStyle で fontWeight や fontStyle を指定しても、それに対応するフォントファイルが pubspec.yaml に定義されていない場合、Flutter のエンジンはデフォルトのフォントを使用して、太字やイタリック体などをシミュレートします。
② このシミュレーションは実際のフォントファイルのスタイルとは異なるため、視覚的に期待した通りのフォント表示にならないことがあります。

故に、シミュレートに頼らず、正しいフォントファイルを用意して pubspec.yaml に定義することを推奨しています。特に、太字やイタリック体などのスタイルを使用する場合は、該当するフォントファイルを用意し、それを fonts の style または weight プロパティで指定するようにしましょう。

6.実施例

(1)フォントのダウンロード

Google Fonts からRalewayとRobotoMonoのフォントファイルをダウンロードして下さい。

(2)pubspec.yaml ファイルの更新

pubspec.yaml に、フォントファイルを宣言する例:
name: custom_fonts
description: An example of how to use custom fonts with Flutter

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  fonts:
    - family: Raleway
      fonts:
        - asset: fonts/Raleway-Regular.ttf
        - asset: fonts/Raleway-Italic.ttf
          style: italic
    - family: RobotoMono
      fonts:
        - asset: fonts/RobotoMono-Regular.ttf
        - asset: fonts/RobotoMono-Bold.ttf
          weight: 700
  uses-material-design: true

(3)main.dart ファイルでの利用

main.dart ファイルでの利用例:
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Fonts',
      //デフォルトフォントに Raleway を設定します
      theme: ThemeData(fontFamily: 'Raleway'),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //設定済みのデフォルトフォント( Releway )を使用します
      appBar: AppBar(title: const Text('Custom Fonts')),
      body: const Center(
        //Textウィジェットで、RobotoMono フォントを使用します
        child: Text(
          'Roboto Mono sample',
          style: TextStyle(fontFamily: 'RobotoMono'),
        ),
      ),
    );
  }
}

コメントを残す