【Flutter】動的にテーマを変更する【flutter_riverpod】

ネコニウム研究所

PCを利用したモノづくりに関連する情報や超個人的なナレッジを掲載するブログ

【Flutter】動的にテーマを変更する【flutter_riverpod】

2024-5-26 | ,

Flutterで動的にテーマを変更したい!

概要

今回の記事では、Flutterで動的にテーマを変更する手順を掲載する。

仕様書

環境

  • Android Studio Giraffe | 2023.2.1 Patch 2
  • Flutter 3.19.6
  • flutter_riverpod: 2.5.1

手順書

インストール編とコード編の2部構成です。

インストール編

ターミナルでコマンドを実行するか

flutter pub add flutter_riverpod

pubspec.yamldependencies:に下記のような感じで追加して

dependencies:
  flutter_riverpod: ^2.5.1

ターミナルでflutter pub getする。

flutter pub get

コード編

'DropdownButton`でテーマを選択するとテーマが動的に変更される例。

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

Brightness getTheme(BuildContext context, String str) {
  switch (str) {
    case "light":
      return Brightness.light;
    case "dark":
    return Brightness.dark;
    case "device":
    default:
      return MediaQuery.platformBrightnessOf(context);
  }
}

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final theme = ref.watch(themeStateNotifierProvider);

    return MaterialApp(
        title: 'Flutter Test',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(
              seedColor: Colors.deepPurple,
              brightness: getTheme(context, theme)),
          useMaterial3: true,
        ),
        home: Scaffold(
            body: DynamicThemeSample1( deviceTheme: MediaQuery.platformBrightnessOf(context), )
        )
    );
  }
}

final themeStateNotifierProvider =
StateNotifierProvider<ThemeStateNotifier, String>((ref) {
  return ThemeStateNotifier();
});

class ThemeStateNotifier extends StateNotifier<String> {
  ThemeStateNotifier() : super("device");
  void update(String theme) {
    state = theme;
  }
}

class DynamicThemeSample1 extends StatefulWidget {
  final Brightness deviceTheme;
  const DynamicThemeSample1({super.key, required this.deviceTheme});

  @override
  DynamicThemeState createState() => DynamicThemeState();
}

class DynamicThemeState extends State<DynamicThemeSample1> {
  String selectedTheme = 'device';

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Center(
        child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
          Text(
            AppLocalizations.of(context)!.hello,
          ),
          Consumer(
            builder: (BuildContext context, WidgetRef ref, Widget? child) {
              return DropdownButton<String>(
                value: selectedTheme,
                onChanged: (String? value) {
                  setState(() {
                    selectedTheme = value ?? "device";
                  });

                  ref
                      .read(themeStateNotifierProvider.notifier)
                      .update(selectedTheme);
                },
                items:  [
                  DropdownMenuItem(
                    value: 'device',
                    child: Text('デバイスの設定を使う(${widget.deviceTheme == Brightness.light ? "Light" : "Dark" })'),
                  ),
                  const DropdownMenuItem(
                    value: 'light',
                    child: Text('Light'),
                  ),
                  const DropdownMenuItem(
                    value: 'dark',
                    child: Text('Dark'),
                  ),
                ],
              );
            },
          ),
        ]),
      ),
    );
  }
}

親のMaterialAppのプロパティを動的に変更するためにfullter_riverpodStateNotifierProviderを使ってる。()

まとめ(感想文)

APIにアクセスするとかネットワークを使う場合に特に便利だ!