[読書会]テーマによる色やフォントスタイルの共有

アプリ全体で色やフォントのスタイルを共有するには、テーマを使用します。

アプリ全体のテーマを定義できます。 テーマを拡張して、1つのコンポーネントのテーマスタイルを変更できます。 各テーマは、マテリアルコンポーネントのタイプに適用される色、タイプスタイル、およびその他のパラメータを定義します。

flutterは以下の順序でスタイルを適用します。

  1. 特定のウィジェットに適用されるスタイル。
  2. 直接の親テーマをオーバーライドするテーマ。
  3. アプリ全体のメインテーマ。

テーマを定義したら、それを自分のウィジェット内で使用します。
FlutterのMaterialウィジェットは、アプリバー、ボタン、チェックボックスなどの背景色やフォントスタイルを設定する為にテーマを使います。

1.アプリテーマの作成

アプリ全体でテーマを共有するには、MaterialAppコンストラクタにthemeプロパティを設定します。
このプロパティはThemeDataインスタンスを取ります。

Flutter 3.16リリースの時点で、Material 3がFlutterのデフォルトテーマとなっています。

コンストラクタでテーマを指定しない場合、Flutterはデフォルトのテーマを作成します。

ThemeDataによるテーマの作成例:
MaterialApp(
  title: appName,
  //themeプロパティ: アプリ全体のテーマを設定します。
  theme: ThemeData(
    useMaterial3: true,
    //colorSchemeプロパティ: アプリ内のウィジェットで使用される色が一括で設定され、
    //各要素(ボタン、背景色、テキスト色など)が同じ配色で統一されます。
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.purple,
      brightness: Brightness.dark,
    ),
    //textThemeプロパティ: 各テキストの役割に応じてスタイルを設定できます。
    //(例: displayLarge、titleLarge、bodyMedium など)。
    textTheme: TextTheme(
      displayLarge: const TextStyle(
        fontSize: 72,
        fontWeight: FontWeight.bold,
      ),
      titleLarge: GoogleFonts.oswald(
        fontSize: 30,
        fontStyle: FontStyle.italic,
      ),
      bodyMedium: GoogleFonts.merriweather(),
      displaySmall: GoogleFonts.pacifico(),
    ),
  ),
  home: const MyHomePage(title: appName),
);

ThemeDataのほとんどのインスタンスは、以下の2つのプロパティの値を設定します。これらのプロパティはアプリ全体に影響します。

どのような色、フォント、その他のプロパティを定義できるかについては、ThemeDataのドキュメントを参照してください。

2.テーマの適用

新しいテーマを適用するには、ウィジェットのスタイリングプロパティを指定する際に、Theme.of(context)メソッドを使用します。 これには、スタイルと色が含まれますが、これらに限定されません。

Theme.of(context)メソッドは、ウィジェットツリーを検索し、ツリーの中で最も近いTheme取得します。 スタンドアロンのThemeがあれば、それが適用されます。 そうでない場合、Flutterはアプリのテーマを適用します。

次の例では、Containerコンストラクタがこのテクニックを使って色を設定しています。

Theme.of(context)メソッドで、Containerの色テーマを設定する例:
Container(
  padding: const EdgeInsets.symmetric(
    horizontal: 12,
    vertical: 12,
  ),
  //Container の背景色を設定しています。
  //テーマのカラースキーム(ColorScheme)の primary 色
  //が取得され、Container の背景色として設定されています。
  //これにより、アプリのテーマに基づいた色が自動的に適用
  //されるため、テーマを変更した場合でも、
  //色が一括で反映されます。
  color: Theme.of(context).colorScheme.primary,
  child: Text(
    'Text with a background color',
    style: Theme.of(context).textTheme.bodyMedium!.copyWith(
      color: Theme.of(context).colorScheme.onPrimary,
    ),
  ),
)
ボタンのスタイル設定例:
ElevatedButton(
  onPressed: () {},
  //ボタンの背景色をテーマの secondary 色に設定
  style: ElevatedButton.styleFrom(
    primary: Theme.of(context).colorScheme.secondary,
  ),
  child: Text('テーマ適用ボタン'),
)
アイコンのスタイル設定例:
Icon(
  Icons.favorite,
  //アイコンの色をテーマの primary 色に設定
  color: Theme.of(context).colorScheme.primary,
)
テキストフィールドのスタイル設定例:
TextField(
  decoration: InputDecoration(
    hintText: 'テーマに基づくヒントテキスト',
    //ヒントテキストのスタイルをテーマに基づいて設定
    hintStyle: Theme.of(context).textTheme.bodyMedium,
  ),
)

3.テーマの上書き

ここでは、Flutter のテーマを一部のウィジェットに対して上書きする方法について述べています。
通常、アプリ全体適用されているテーマThemeData)を使用しますが、特定の部分スタイル変更したい場合や、アプリ全体のテーマを無視して独自のスタイルを適用したい場合に、この方法を使います。

テーマの上書き方法(2つの方法)

  1. 独自のThemeDataインスタンスを作成する。
  2. 親テーマを拡張する。

(方法1)独自のThemeDataインスタンスを作成する

特定のコンポーネントやウィジェットが、アプリ全体のテーマを無視して独自のスタイルを持つようにしたい場合、この方法を使用します。

  • Theme ウィジェットを使って、新しい ThemeData インスタンスを作成し、その data プロパティに渡します。
  • これにより、Theme ウィジェットchild 指定されたウィジェットには、親テーマ(アプリ全体のテーマ)とは異なるスタイルが適用されます。
Theme ウィジェット内に ThemeData を直接作成し、FloatingActionButton に適用する例:
//この例では、Theme ウィジェット内に ThemeData を直接作成し、
//FloatingActionButton に適用しています。
Theme(
  //独自のテーマを `ThemeData` で作成して渡す
  data: ThemeData(
    //この ThemeData は、ピンク色を基調としたカラースキーム
    //(ColorScheme.fromSeed(seedColor: Colors.pink))
    //を持ちます。
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.pink,
    ),
  ),
  //この FloatingActionButton のスタイルは
  //アプリ全体のテーマとは異なり、独立したテーマが適用されます。
  child: FloatingActionButton(
    onPressed: () {},
    child: const Icon(Icons.add),
  ),
);

上記は、
・特定のボタンやコンポーネントに異なるカラースキームやテキストスタイルを適用したい時
・ダークテーマやライトテーマの中でも、特定の要素だけに違う色を適用したい時
等に有効です。

(方法2)親テーマを拡張する

親テーマスタイル保持しつつ特定スタイル上書きしたい場合には、親テーマを拡張(copyWith メソッドを使用)します。

  • Theme.of(context).copyWith を使うことで、親テーマのスタイルを維持したまま特定のプロパティのみを上書きできます。
  • これにより、例えば既存のテキストスタイルや背景色を保持しながら、特定のコンポーネントだけの色やスタイルを変更できます。
Theme.of(context).copyWith() を使って、現在の親テーマを拡張する例:
Theme(
  //親テーマを拡張して上書きする
  data: Theme.of(context).copyWith(
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.pink,
    ),
  ),
  child: const FloatingActionButton(
    onPressed: null,
    child: Icon(Icons.add),
  ),
);

上記は、
現在のテーマ(親テーマ)をベースにしつつ、一部の色やフォントだけを変更したい時
テーマ全体を変更するのではなく、特定のウィジェットのプロパティだけを微調整したい時
等に有効です。

このビデオでは、2つのテーマ(Light and Dark theme)を併用したい場合の対応について述べられています。

コメントを残す