LoginSignup
6
5

More than 3 years have passed since last update.

Flutterでデバイスのテーマを取得してアプリのテーマを切り替える

Last updated at Posted at 2019-11-21

iOS13からダークモードが増え、アプリで対応する必要が出てきたので対応方法を考えてみました。
下記でデバイスのテーマ設定を取得できる

platformBrightness = MediaQuery.platformBrightnessOf(context);

InheritedWidgetを使用して、アプリのテーマを切り替える

2020年4月30日追記
inheritFromWidgetOfExactTypeは非推奨のAPIになりました
これからはdependOnInheritedWidgetOfExactTypeを使用してください

class ThemeSwitcher extends InheritedWidget {
  const ThemeSwitcher({
    Key key,
    @required this.data,
    @required Widget child,
  })  : assert(child != null),
        super(key: key, child: child);

  final _ThemeSwitcherWidgetState data;
  static _ThemeSwitcherWidgetState of(BuildContext context) {
    final ThemeSwitcher _themeswitcher =
        context.dependOnInheritedWidgetOfExactType<ThemeSwitcher>();
    return _themeswitcher.data;
  }

  @override
  bool updateShouldNotify(ThemeSwitcher widget) => this != widget;

class ThemeSwitcherWidget extends StatefulWidget {
  const ThemeSwitcherWidget({
    Key key,
    @required this.child,
    @required this.initialThemeMode,
  })  : assert(child != null),
        assert(initialThemeMode != null),
        super(key: key);

  final Widget child;
  final ThemeMode initialThemeMode;

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

class _ThemeSwitcherWidgetState extends State<ThemeSwitcherWidget> {
  final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
  ThemeMode themeMode = ThemeMode.light;

  @override
  void initState() {
    super.initState();
    loadAppTheme();
  }

  Future<void> loadAppTheme() async {
    final SharedPreferences prefs = await _prefs;
    if (prefs.getBool('isDark') == null) {
      // 初回起動は端末のテーマ情報を取得しアプリに適用する
      final Brightness platformBrightness =
          MediaQuery.platformBrightnessOf(context);
      switchTheme(platformBrightness == Brightness.dark);
    } else {
      setState(() {
        themeMode = prefs.getBool('isDark') ? ThemeMode.dark : ThemeMode.light;
      });
    }
  }

  Future<void> switchTheme(bool val) async {
    final SharedPreferences prefs = await _prefs;
    prefs.setBool('isDark', val);
    setState(() {
      themeMode = val ? ThemeMode.dark : ThemeMode.light;
    });
  }

  @override
  Widget build(BuildContext context) {
    themeMode = themeMode ?? widget.initialThemeMode;
    return ThemeSwitcher(
      data: this,
      child: widget.child,
    );
  }
}

使い方

void main( {
  runApp(
    const ThemeSwitcherWidget(
      initialThemeMode: ThemeMode.light,
      child: App(),
    ),
  );
}
class App extends StatelessWidget {
  const App({key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      thememode: ThemeSwitcher.of(context).themeMode,
      home: home(),
    );
  }
}

下記を呼び出してテーマを変更し、アプリ全体に反映する

ThemeSwitcher.of(context).switchTheme(val);
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5