Flutter テーマとスタイル

このセクションでは、Flutter のテーマ設定について紹介します。Material Design テーマ、カスタムテーマ、ダークモードなどが含まれます。


ThemeData - テーマの適用

ThemeData を使用すると、アプリのテーマカラー、フォント、スタイルなどを一括で設定できます。

例:アプリテーマの構成

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(
        // メインカラー
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.light,
        ),
        // Material 3 を使用
        useMaterial3: true,
        // フォント
        fontFamily: 'Roboto',
        // アプリバーテーマ
        appBarTheme: const AppBarTheme(
          centerTitle: true,
          elevation: 0,
        ),
        // ボタンテーマ
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
          ),
        ),
        // 入力フィールドのテーマ
        inputDecorationTheme: InputDecorationTheme(
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(8),
          ),
          filled: true,
        ),
      ),
      home: const MyHomePage(),
    ),
  );
}

Theme.of - テーマの使用

Widget 内で Theme.of(context) を使用して現在のテーマを取得します。

例:テーマカラーの使用

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

  @override
  Widget build(BuildContext context) {
    // テーマを取得
    final theme = Theme.of(context);

    return Column(
      children: [
        // テーマカラーを使用
        Container(
          color: theme.colorScheme.primary,
          padding: const EdgeInsets.all(16),
          child: Text(
            'メインカラー',
            style: TextStyle(color: theme.colorScheme.onPrimary),
          ),
        ),
        const SizedBox(height: 16),
        // サブカラーを使用
        Container(
          color: theme.colorScheme.secondary,
          padding: const EdgeInsets.all(16),
          child: Text(
            'サブカラー',
            style: TextStyle(color: theme.colorScheme.onSecondary),
          ),
        ),
        const SizedBox(height: 16),
        // エラーカラーを使用
        Container(
          color: theme.colorScheme.error,
          padding: const EdgeInsets.all(16),
          child: Text(
            'エラーカラー',
            style: TextStyle(color: theme.colorScheme.onError),
          ),
        ),
      ],
    );
  }
}

ダークモード

例:ダークモードのサポート

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(
        // ライトテーマ
        brightness: Brightness.light,
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
      ),
      darkTheme: ThemeData(
        // ダークテーマ
        brightness: Brightness.dark,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
        ),
      ),
      // 同時に有効にする(オプション)
      themeMode: ThemeMode.system,  // システム設定に従う
      // themeMode: ThemeMode.light // ライトモードを強制
      // themeMode: ThemeMode.dark // ダークモードを強制
      home: const ThemeTogglePage(),
    ),
  );
}

// テーマの切り替え
class ThemeTogglePage extends StatelessWidget {
  const ThemeTogglePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('テーマ切り替え')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('現在のテーマ'),
            const SizedBox(height: 20),
            // テーマ切り替えボタン
            ElevatedButton(
              onPressed: () {
                final currentMode = Theme.of(context).brightness;
                if (currentMode == Brightness.light) {
                  // ダークに切り替え
                  Theme.of(context).setThemeMode(ThemeMode.dark);
                } else {
                  // ライトに切り替え
                  Theme.of(context).setThemeMode(ThemeMode.light);
                }
              },
              child: const Text('テーマを切り替え'),
            ),
          ],
        ),
      ),
    );
  }
}

カスタムスタイルの拡張

例:カスタム TextTheme

ThemeData(
  textTheme: const TextTheme(
    // 表示テキスト(大見出し)
    displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.w400),
    displayMedium: TextStyle(fontSize: 45, fontWeight: FontWeight.w400),
    displaySmall: TextStyle(fontSize: 36, fontWeight: FontWeight.w400),
    // 見出しテキスト
    headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.w400),
    headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w400),
    headlineSmall: TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
    // 見出しテキスト
    titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
    titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
    titleSmall: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
    // 本文テキスト
    bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
    bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
    bodySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
    // ラベルテキスト
    labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
    labelMedium: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
    labelSmall: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
  ),
)

ThemeData を使用してアプリのスタイルを一元的に管理すると、テーマの切り替えやスタイルの統一を簡単に実現でき、保守もより便利になります。

その他の拡張