ThemeとThemeData — その概念とスタイル設定の原則

著者: IT Sectr 公開日: 2026-07-03 読了時間: 8 分

ThemeThemeData — Flutterにおけるテーマ設定の中核メカニズムで、アプリケーション全体の色、フォント、余白、コンポーネントスタイルをグローバルに定義できます。ThemeDataはthemeパラメータを介してMaterialAppに渡される設定オブジェクトです。公式Flutterドキュメント(2026年)によると、ThemeDataを適切に設定すると、重複するスタイルコードが70〜80%削減され、全画面で統一された外観が保証されます。組み込みの継承システムにより、Theme.of(context)を介して個々のウィジェットレベルでテーマを上書きできます。

重要なポイント

  • ThemeData — カラーパレット、タイポグラフィ、コンポーネントスタイルを含む設定オブジェクト
  • Theme.of(context) — BuildContextを介して任意のウィジェットから現在のテーマにアクセス
  • Light/Dark — themeとdarkThemeによるライト/ダークテーマの組み込みサポート
  • Theme — 子要素にテーマを継承し、上書きを可能にするウィジェット
  • ColorScheme — Materialシステム全体のスタイルを生成する調和のとれた色のセット

ThemeとThemeDataとは

ThemeDataは、Materialアプリケーションのビジュアルスタイルの完全な記述を含むクラスです。themeまたはdarkThemeパラメータを介してMaterialAppに渡され、すべての子ウィジェットに継承されます。すべてのMaterial Designウィジェットは、ThemeDataを使用してスタイル(ボタンの色、AppBarのサイズ、テキストスタイル、カードの余白、アイコン)を取得します。

ThemeDataの中核にはColorSchemeがあり、primary、secondary、surface、errorなどの色を定義します。これらの色から、すべてのMaterialコンポーネントの状態(ホバー、フォーカス、プレス)が自動的に計算されます。たとえば、ElevatedButtonは背景にprimary色、テキストにonPrimaryを使用します — 追加設定は不要です。

ThemeウィジェットはInheritedWidgetで、テーマをウィジェットツリーの下位に伝播します。任意のウィジェットはTheme.of(context)を介して現在のテーマにアクセスでき、Theme.copyWithまたはThemeData.copyWithを介して既存のテーマをベースに上書きした値で新しいテーマを作成することもできます。

まとめ: ThemeDataはアプリケーションのスタイルの単一ソースです。開発はThemeDataを定義することから始めましょう — これによりプロジェクト全体のビジュアル言語が設定され、異なる画面でスタイルが分散するのを防ぎます。

ColorScheme: カラーパレットの基礎

ColorSchemeはMaterial 3におけるテーマ設定の中核要素です。非推奨のprimarySwatchとprimaryColorを置き換え、すべての状態とコンポーネントに完全な色のセットを提供します。

ColorSchemeには12の主要色があります: primary、onPrimary、secondary、onSecondary、surface、onSurface、error、onError、background、onBackground、outline、shadow。各色に対して、明るいバリアントと暗いバリアント、およびホバー、フォーカス、プレス、ドラッグ状態の色が自動的に計算されます。primaryのみを指定すると、フレームワークはColorScheme.fromSeedを介して残りの色を自動生成します。

ColorScheme.fromSeedメソッド(Material 3)は、ベースカラーseedColorを受け取り、Material Design 3アルゴリズムに基づいて完全な調和のとれたパレットを生成します。これにより、補色や類似色を手動で選択する必要がなくなります。ブランドの主要色を1つ渡すだけで、ColorScheme.fromSeedがMaterialシステム全体の一貫したパレットを作成します。

まとめ: 新しいプロジェクトでは、パレット生成にColorScheme.fromSeedを使用してください。Material 2互換性の場合は — primarySwatchを使用します。ColorSchemeはMaterial 3の最小要件です。

タイポグラフィとTextTheme: アプリのフォント

TextThemeはThemeDataの一部で、すべての見出しレベル、小見出し、本文、ラベルのテキストスタイルを定義します。Material Designは15のテキストスタイルを定義しています: headlineLarge、headlineMedium、headlineSmall、titleLarge、titleMediumなど。

タイポグラフィは、GoogleFontsによる自動フォント読み込み、またはカスタムTextStyleオブジェクトを使用した組み込みのTheme.of(context).textThemeを介して設定されます。GoogleFontsはgoogle_fontsパッケージを通じて数百のフォントを提供し、初回読み込み後にローカルにキャッシュします。代替方法は、pubspec.yamlを介してフォントをプロジェクトのアセットに埋め込むことです。

アダプティブタイポグラフィのために、TextThemeはMediaQuery.textScaleFactorをサポートしています — システムフォントサイズが増加すると、すべてのテキストスタイルが比例して拡大縮小されます。さらに、MediaQuery.size.widthに応じてisTestを使用して、異なるフォームファクターに異なるフォントサイズを設定できます。

まとめ: ThemeDataでTextThemeを定義し、すべてのテキスト要素にTheme.of(context).textThemeを使用してください。これによりフォントの一貫性が確保され、グローバルなタイポグラフィ変更が簡素化されます。

テーマの継承と上書き

ThemeはInheritedWidgetで、テーマを親から子へ伝播します。子ウィジェットはTheme.of(context)を介して現在のテーマを読み取るだけでなく、ThemeData.copyWithを介して変更を加えた独自のコピーを作成することもできます。

継承メカニズム: ウィジェットが新しいデータを持つThemeでラップされている場合、そのすべての子孫は上書きされたテーマを参照し、このラッパーの外側のウィジェットは元のテーマを参照します。これにより、特定の画面のスタイルを分離できます: ヘッダーは変更されたAppBarThemeを持つカスタムテーマを使用し、アプリの残りの部分は標準テーマを使用します。

Themeのネストは無制限です。Flutterは階層的な検索を使用します: Theme.of(context)が呼び出されると、フレームワークはツリーを上って最初のThemeまで移動し、そのテーマを返します。Themeが見つからない場合は — 例外がスローされます。したがって、MaterialAppは常にアプリケーションをThemeでラップします。

まとめ: Themeの継承はスタイル分離のための柔軟なメカニズムです。グローバル設定を複製することなく、個々の画面にテーマの上書きを使用してください。

ダークテーマ: アプリのダークモード

ダークテーマは、Flutterのライトテーマとダークテーマを切り替える組み込み機能です。ThemeDataはMaterialAppのtheme(ライト)とdarkTheme(ダーク)パラメータに格納されます。themeModeパラメータがモードを制御します: ThemeMode.light(常にライト)、ThemeMode.dark(常にダーク)、ThemeMode.system(システム設定に従う)。

ダークテーマを実装する際、すべてのスタイルをゼロから再作成する必要はありません。単にColorScheme.fromSeed(seedColor, brightness: Brightness.dark)をdarkThemeに渡します。フレームワークは自動的にダーク背景用に色を調整します: surfaceはダークグレーに、テキストは明るくなります。他のサブテーマ(AppBarTheme、CardTheme、BottomNavigationBarTheme)は、明示的に上書きされない限り、ライトバージョンから継承されます。

テーマ間のスムーズな遷移のために、FlutterはAnimatedThemeを介したアニメーションを提供します。themeModeが変更されると、色とスタイルがアニメーションし、視覚的に魅力的な切り替えを実現します。AnimatedThemeはDurationとCurveを使用してアニメーション速度を設定します。

まとめ: ダークテーマはdarkThemeとColorScheme.fromSeed(brightness: Brightness.dark)を使用して実装します。ユーザーのシステム設定に従うにはThemeMode.systemを使用します。

ThemeとThemeDataのコード例

例1 — ColorScheme.fromSeedを使用したMaterialAppを介したグローバルテーマ設定。

dart
final ThemeData appTheme = ThemeData(
  useMaterial3: true,
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.indigo,
    brightness: Brightness.light,
  ),
  appBarTheme: const AppBarTheme(
    centerTitle: true,
    elevation: 0,
  ),
  cardTheme: const CardTheme(
    elevation: 2,
    margin: EdgeInsets.all(8),
  ),
);

return MaterialApp(
  theme: appTheme,
  themeMode: ThemeMode.system,
  home: const MyHomePage(),
);

この例では、Material 3、インディゴベースのカラースキーム、カスタムのAppBarとCardスタイルを持つThemeDataを作成します。useMaterial3は新しいMaterial 3テーマシステムを有効にし、ColorScheme.fromSeedが完全なパレットを生成します。

例2 — テーマへのアクセスとアプリケーションの一部の上書き。

dart
Widget build(BuildContext context) {
  final theme = Theme.of(context);

  return Column(
    children: [
      Text(
        'Standard headline',
        style: theme.textTheme.headlineMedium,
      ),
      Theme(
        data: theme.copyWith(
          colorScheme: theme.colorScheme.copyWith(
            primary: Colors.orange,
          ),
        ),
        child: const SpecialSection(),
      ),
    ],
  );
}

2つ目の例では、Theme.of(context)を使用したスタイルの読み取りと、グローバル設定を変更せずにツリーの一部でテーマを上書きするためのcopyWith付きTheme()の使用を示しています。Theme内のSpecialSectionはオレンジのprimary色を受け取り、アプリの残りの部分は元のインディゴを維持します。

まとめ: グローバルテーマはMaterialAppで設定し、Theme.of(context)を介してアクセスし、copyWith付きのThemeを介して上書きします。Material 3の場合はColorScheme.fromSeedを使用します。

テーマ設定のよくある間違い

間違い1: Material 3でColorSchemeの代わりにprimarySwatchを使用する。primarySwatchは非推奨で、Material 3ではサポートされていません。primarySwatchでuseMaterial3: trueを使用すると、Flutterは警告を発します。解決策: パレット生成にColorScheme.fromSeedに移行してください。

間違い2: Theme.of(context)を使用せずにウィジェットに色をハードコードする。開発者はテーマのprimaryやsecondary色を使わずに、Containerに直接Colors.blueと書きます。テーマが変更されても、これらの色は変わらず、一貫性が損なわれます。解決策: 常にTheme.of(context).colorScheme.primaryまたはテーマの他の色を使用してください。

間違い3: darkThemeの欠如。アプリケーションがdarkThemeを定義していない場合、デバイスでダークテーマが有効になると、Flutterは自動的にライトテーマを適応させようとしますが、多くの場合、品質の低い結果になります。解決策: ダークテーマが優先事項でなくても、常にMaterialAppにdarkThemeを渡してください — これはユーザーにとって重要なUXです。

間違い4: ビルドごとに新しいテーマを作成する。ThemeDataがbuildメソッド内で作成されると、ウィジェットが再構築されるたびに新しいテーマオブジェクトが作成され、InheritedWidgetの最適化が損なわれます。解決策: ThemeDataをbuildの外側のstaticフィールドまたはconstコンストラクタに移動してください。

まとめ: 適切なテーマ設定には集中管理アプローチが必要です。ThemeDataを定数に移動し、テーマのカラースキームを使用し、常にライトとダークの両方のテーマを定義してください。

よくある質問

ThemeとThemeDataの違いは何ですか?

ThemeDataは設定データ(色、フォント、スタイル)です。ThemeはThemeDataをウィジェットツリーの下位に渡すInheritedWidgetです。Theme.of(context)は、現在のコンテキストで最も近いThemeが伝播するThemeDataを返します。

アプリのテーマを動的に切り替えるには?

アプリケーションの状態を介してMaterialAppのthemeModeを制御します。状態をThemeMode.lightからThemeMode.darkに変更すると、Flutterは新しいテーマでツリー全体を再構築します。スムーズなアニメーションにはAnimatedThemeを使用します。

ColorScheme.fromSeedとは何ですか?

ColorScheme.fromSeedはMaterial 3のメソッドで、1つのベースカラー(seedColor)を受け取り、完全な調和のとれたパレット(primary、secondary、tertiary、surface、errorとそのonバリアント)を生成します。1つのブランドカラーから一貫したカラースキームを生成できます。

Themeでカスタムフォントを使用するには?

ThemeData内のTextThemeを介して: 各レベルにfontFamilyを指定したTextStyleを設定します。Google Fontsの場合は、google_fontsパッケージを使用し、fontFamilyを直接TextThemeに渡します。ローカルフォントの場合は — pubspec.yamlのfontsセクションでそれらを含めます。

1つの画面だけテーマを上書きできますか?

はい。copyWithを介して上書きしたデータを持つThemeで画面をラップします。このTheme内のすべての子ウィジェットは変更されたスタイルを受け取り、アプリの残りの部分は元のテーマを維持します。追加のオーバーヘッドは発生しません。

まとめ

  • ThemeData — すべてのMaterialコンポーネントのカラーパレット、タイポグラフィ、スタイルを含む設定オブジェクト
  • ColorScheme.fromSeed — 単一のブランドカラーからMaterial 3でカラーパレットを生成する主要な方法
  • Theme.of(context) — コードの重複なしにスタイルを読み取るための現在のテーマへのアクセス
  • Theme — ウィジェットのサブツリーでテーマを継承および上書きするためのInheritedWidget
  • ダークテーマ — brightness: Brightness.darkの個別のThemeData、themeModeで制御
  • 推奨: ThemeDataをstaticまたはconstに移動し、MaterialAppで常にthemeとdarkThemeを定義する

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください