如何在flutter中实现Dark mode和Light Mode?

How to implement Dark mode and Light Mode in flutter?

我想创建一个 flutter 应用程序,它有 2 个明暗模式主题,通过应用程序内的开关改变,默认主题是默认 android 主题。
我需要将一些自定义颜色传递给其他小部件,我不想只配置 material 主题。

MaterialApp(
  theme: ThemeData.light(),
  /// theme: ThemeData.dark(),
)

在小部件树下,您只需编写 Theme.of(context) 即可访问 ThemeData。如果你想访问当前的 ThemeData 并为某个字段提供你自己的样式,你可以这样做:

Widget build(BuildContext context) {
  var themeData = Theme.of(context).copyWith(scaffoldBackgroundColor: darkBlue)

  return Scaffold(
    backgroundColor = themeData.scaffoldBackgroundColor,
  );
}

但是要处理 ThemeData 状态(更改其值),您需要实施适当的状态管理。

使用 Material 应用程序

MaterialApp(
      title: 'App Title',
      theme: ThemeData(
        brightness: Brightness.light,
        /* light theme settings */
      ),
      darkTheme: ThemeData(
        brightness: Brightness.dark,
        /* dark theme settings */
      ),
      themeMode: ThemeMode.dark, 
      /* ThemeMode.system to follow system theme, 
         ThemeMode.light for light theme, 
         ThemeMode.dark for dark theme
      */
      debugShowCheckedModeBanner: false,
      home: YourAppHomepage(),
    );

使用 CupertinoApp

  1. 检测黑暗模式使用,WidgetsBinding.instance?.window.platformBrightness

  2. 您可能还需要监听系统的亮度变化,以便使用 WidgetsBindingObserver 和覆盖 didChangePlatformBrightness();[=16= 进行实时更新]

CupertinoApp 示例:

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  Brightness? _brightness;

  @override
  void initState() {
    WidgetsBinding.instance?.addObserver(this);
    _brightness = WidgetsBinding.instance?.window.platformBrightness;
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangePlatformBrightness() {
    if (mounted) {
      setState(() {
        _brightness = WidgetsBinding.instance?.window.platformBrightness;
      });
    }

    super.didChangePlatformBrightness();
  }

  CupertinoThemeData get _lightTheme =>
      CupertinoThemeData(brightness: Brightness.light, /* light theme settings */);

  CupertinoThemeData get _darkTheme => CupertinoThemeData(
        brightness: Brightness.dark, /* dark theme settings */,
      );

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      title: 'Demo App',
      theme: _brightness == Brightness.dark ? _darkTheme : _lightTheme,
      home: MyHomePage(title: 'Demo Home Page'),
    );
  }
}

您可以使用 scoped_model, provider, bloc or get 获得无缝体验。

我认为最简单的方法是使用提供程序来管理您的应用程序的状态,并 shared_preferences 将您的主题偏好保存在文件系统上。按照此过程,您可以保存主题,这样用户就不必每次都切换主题。

输出

您可以轻松地以字符串的形式存储您的主题首选项,然后在您的应用启动时检查文件系统中是否存储了值,如果有则应用该主题,如下所示。

StorageManager.dart

import 'package:shared_preferences/shared_preferences.dart';

class StorageManager {
  static void saveData(String key, dynamic value) async {
    final prefs = await SharedPreferences.getInstance();
    if (value is int) {
      prefs.setInt(key, value);
    } else if (value is String) {
      prefs.setString(key, value);
    } else if (value is bool) {
      prefs.setBool(key, value);
    } else {
      print("Invalid Type");
    }
  }

  static Future<dynamic> readData(String key) async {
    final prefs = await SharedPreferences.getInstance();
    dynamic obj = prefs.get(key);
    return obj;
  }

  static Future<bool> deleteData(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.remove(key);
  }
}

在主题变量中定义主题属性,如下所示,并根据存储中的值初始化 _themedata 变量。

ThemeManager.dart

import 'package:flutter/material.dart';
import '../services/storage_manager.dart';

class ThemeNotifier with ChangeNotifier {
  final darkTheme = ThemeData(
    primarySwatch: Colors.grey,
    primaryColor: Colors.black,
    brightness: Brightness.dark,
    backgroundColor: const Color(0xFF212121),
    accentColor: Colors.white,
    accentIconTheme: IconThemeData(color: Colors.black),
    dividerColor: Colors.black12,
  );

  final lightTheme = ThemeData(
    primarySwatch: Colors.grey,
    primaryColor: Colors.white,
    brightness: Brightness.light,
    backgroundColor: const Color(0xFFE5E5E5),
    accentColor: Colors.black,
    accentIconTheme: IconThemeData(color: Colors.white),
    dividerColor: Colors.white54,
  );

  ThemeData _themeData;
  ThemeData getTheme() => _themeData;

  ThemeNotifier() {
    StorageManager.readData('themeMode').then((value) {
      print('value read from storage: ' + value.toString());
      var themeMode = value ?? 'light';
      if (themeMode == 'light') {
        _themeData = lightTheme;
      } else {
        print('setting dark theme');
        _themeData = darkTheme;
      }
      notifyListeners();
    });
  }

  void setDarkMode() async {
    _themeData = darkTheme;
    StorageManager.saveData('themeMode', 'dark');
    notifyListeners();
  }

  void setLightMode() async {
    _themeData = lightTheme;
    StorageManager.saveData('themeMode', 'light');
    notifyListeners();
  }
}

使用 themeProvider 包装您的应用,然后使用消费者应用主题。每当您更改主题的值并调用通知侦听器小部件重建以同步更改时这样做。

Main.dart

void main() {
  return runApp(ChangeNotifierProvider<ThemeNotifier>(
    create: (_) => new ThemeNotifier(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeNotifier>(
      builder: (context, theme, _) => MaterialApp(
        theme: theme.getTheme(),
        home: Scaffold(
          appBar: AppBar(
            title: Text('Hybrid Theme'),
          ),
          body: Row(
            children: [
              Container(
                child: FlatButton(
                  onPressed: () => {
                    print('Set Light Theme'),
                    theme.setLightMode(),
                  },
                  child: Text('Set Light Theme'),
                ),
              ),
              Container(
                child: FlatButton(
                  onPressed: () => {
                    print('Set Dark theme'),
                    theme.setDarkMode(),
                  },
                  child: Text('Set Dark theme'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Here 是 link 到 github 存储库。

让系统处理主题:

runApp(
  MaterialApp(
    theme: ThemeData.light(), // Provide light theme
    darkTheme: ThemeData.dark(), // Provide dark theme
    home: HomePage(),
  ),
);

自己处理主题:

使用provider 以编程方式设置主题。完整代码:

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<ThemeModel>(
      create: (_) => ThemeModel(),
      child: Consumer<ThemeModel>(
        builder: (_, model, __) {
          return MaterialApp(
            theme: ThemeData.light(), // Provide light theme.
            darkTheme: ThemeData.dark(), // Provide dark theme.
            themeMode: model.mode, // Decides which theme to show. 
            home: Scaffold(
              appBar: AppBar(title: Text('Light/Dark Theme')),
              body: ElevatedButton(
                onPressed: () => model.toggleMode(),
                child: Text('Toggle Theme'),
              ),
            ),
          );
        },
      ),
    );
  }
}

class ThemeModel with ChangeNotifier {
  ThemeMode _mode;
  ThemeMode get mode => _mode;
  ThemeModel({ThemeMode mode = ThemeMode.light}) : _mode = mode;

  void toggleMode() {
    _mode = _mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }
}

回答 OP 问题:

  • 可以使用以下方式找到当前主题:

    bool isDarkMode = MediaQuery.of(context).platformBrightness == Brightness.dark;
    

    bool isDarkMode = SchedulerBinding.instance.window.platformBrightness == Brightness.dark;
    
  • 您可以为整个应用提供主题,使用 theme 作为默认主题,使用 darkTheme 作为深色主题(如果系统启用了深色模式或您使用 themeMode)

  • 您可以使用上面代码中所示的提供程序包。

截图:


如果你不想使用任何第三方包或插件,你可以使用 ValueListenableBuilder,它是 Flutter 开箱即用的。

完整代码:

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  final ValueNotifier<ThemeMode> _notifier = ValueNotifier(ThemeMode.light);

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: _notifier,
      builder: (_, mode, __) {
        return MaterialApp(
          theme: ThemeData.light(),
          darkTheme: ThemeData.dark(),
          themeMode: mode, // Decides which theme to show, light or dark.
          home: Scaffold(
            body: Center(
              child: ElevatedButton(
                onPressed: () => _notifier.value = mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light,
                child: Text('Toggle Theme'),
              ),
            ),
          ),
        );
      },
    );
  }
}

您也可以使用可用的插件day_night_theme_flutter

一个Flutter插件,可以帮助你随着日出日落自动更换应用的主题。只需指定要使用的浅色和深色主题,一切就绪。您也可以使用自定义的日出和日落时间。

如何使用?

  1. 在你的pubspec.yaml
  2. 中添加最新版本的包
  3. 用 DayNightTheme 小部件包装 MaterialApp。
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.light(), // Provide light theme.
      darkTheme: ThemeData.dark(), // Provide dark theme.
      themeMode: ThemeMode.system,
      home: Scaffold(
        appBar: AppBar(),
        body: Container(),
      ),
    );
  }
}
  theme: ThemeData.light(), // Provide light theme.
  darkTheme: ThemeData.dark(), // Provide dark theme.
  themeMode: ThemeMode.system,


  //use only these three line for dynamic change theme respect to system theme.

这是一个代码
在此代码中,您已根据我的要求制作了自定义主题,您可以更改它!

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Theme',
      debugShowCheckedModeBanner: false,

      /* light theme settings */
      theme: ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: Colors.white,
        brightness: Brightness.light,
        accentColor: Colors.black,
        accentIconTheme: IconThemeData(color: Colors.white),
        dividerColor: Colors.white54,
        scaffoldBackgroundColor: Colors.white,

      ),

      /* Dark theme settings */
      darkTheme: ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: Colors.black,
        brightness: Brightness.dark,
        accentColor: Colors.white,
        accentIconTheme: IconThemeData(color: Colors.black),
        dividerColor: Colors.black12,
        scaffoldBackgroundColor: Color(0xFF131313),

      ),

      /* ThemeMode.system to follow system theme,
         ThemeMode.light for light theme,
         ThemeMode.dark for dark theme */
      themeMode: ThemeMode.system,

      home: MyHomePage(),
    );
  }
}

以下是实现深色模式的三种方法:

  • 总是黑暗模式
  • device/platform 控制黑暗模式
  • 应用程序控制,运行时间可切换黑暗模式

始终暗模式

至 运行 您的应用仅在深色模式下:

  • MaterialApp中,将ThemeData(...)替换为ThemeData.dark()
  • 重新启动您的应用程序。它现在将 运行ning 在深色模式下使用 ThemeData.dark()
  • 中定义的颜色

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(), // default dark theme replaces default light theme
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

设备控制的深色模式

  • 仅适用于 Android 10+、iOS 13+(引入深色模式时)
  • 要让 device/platform 设置主题,MaterialApp 需要 3 个参数:
    • theme: ThemeData()
    • darkTheme: ThemeData().dark
    • themeMode: ThemeMode.system
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(),
      darkTheme: ThemeData.dark(), // standard dark theme
      themeMode: ThemeMode.system, // device controls theme
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
  • (您可以使用自定义主题。为简单起见,以上均为默认主题)
  • themeMode: ThemeMode.system 告诉 Flutter 使用 device/platform 主题设置
  • 在 Android 10+ 或 iOS 13+ 上进行上述设置后,通过设备设置切换暗模式现在会在亮模式和暗模式之间切换您的应用。
  • 只要设备主题发生变化,您的应用就会立即反映所选的设备主题
  • 要以编程方式获取当前设备主题模式,我们可以检查设备亮度(Brightness.lightBrightness.dark),它对应于浅色模式和深色模式。通过查询 platformBrightness 来执行此操作:MediaQuery.of(context).platformBrightness

应用程序控制的深色模式

  • 我们的应用程序可以 运行 亮或暗模式,由用户控制并在应用程序内 运行 时间自由切换,完全忽略设备的主题设置
  • 和以前一样,向 MaterialApp 提供所有三个主题参数:theme:darkTheme:themeMode:,但我们将调整 themeMode: 以使用下面的状态字段
  • 要在应用内切换亮/暗模式,我们将在 ThemeMode.lightThemeMode.dark 之间交换 themeMode: 参数并重建 MaterialApp 小部件。

如何重建 MaterialApp 小部件

  • 要从任何地方切换我们的应用主题,我们需要从我们应用的任何地方访问 MaterialApp
  • 我们可以不使用任何包只使用 StatefulWidget 来做到这一点,或者我们可以使用状态管理包
  • 运行使用下面的 StatefulWidget 在应用中任意位置切换时间主题的示例

之前 - 无状态

  • 我们从这个开始,但我们将用 StatefulWidget 接下来替换它
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(),
      darkTheme: ThemeData.dark(), // standard dark theme
      themeMode: ThemeMode.system, // device controls theme
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

之后 - 有状态

  • 这里我们用 StatefulWidget 和它的补充 State class, _MyAppState[=184= 替换了 MyApp StatelessWidget ]
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(),
      darkTheme: ThemeData.dark(), // standard dark theme
      themeMode: ThemeMode.system, // device controls theme
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

将静态访问器添加到 StatefulWidget

  • 将此静态 of() 方法添加到我们的 StatefulWidget 使其 State 对象可供任何后代小部件访问
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();

  /// ↓↓ ADDED
  /// InheritedWidget style accessor to our State object. 
  static _MyAppState of(BuildContext context) => 
      context.findAncestorStateOfType<_MyAppState>();
}

/// State object hidden ↓. Focusing on ↑ StatefulWidget here.
  • 注意我们的of()方法的returnType_MyAppState
  • 我们没有得到 StatefulWidget,我们得到它的 State 对象:_MyAppState
  • _MyAppState 将保持我们 ThemeMode 设置的“状态”(在下一步中)。这是控制我们应用程序当前主题的内容。
  • 接下来,在我们的 _MyAppState class 中,我们将添加一个 ThemeMode“状态”字段和一种更改主题和重建我们的应用程序的方法

_MyAppState

  • 下面是我们的 State class 修改为:
    1. 一个“状态”字段_themeMode
    2. MaterialApp themeMode: arg 使用 _themeMode 状态字段值
    3. changeTheme方法
class _MyAppState extends State<MyApp> {
  /// 1) our themeMode "state" field
  ThemeMode _themeMode = ThemeMode.system;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(),
      darkTheme: ThemeData.dark(),
      themeMode: _themeMode, // 2) ← ← ← use "state" field here //////////////
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }

  /// 3) Call this to change theme from any context using "of" accessor
  /// e.g.:
  /// MyApp.of(context).changeTheme(ThemeMode.dark);
  void changeTheme(ThemeMode themeMode) {
    setState(() {
      _themeMode = themeMode;
    });
  }
}
  • 接下来,我们将展示如何访问 changeTheme() 以更改我们的主题并重建应用程序

更改主题并重建

  • 下面是使用 of() 访问器方法查找我们的 State 对象并从下面的两个按钮调用其 changeTheme 方法的示例:
    • MyApp.of(context).changeTheme(ThemeMode.light)
    • MyApp.of(context).changeTheme(ThemeMode.dark)
class MyHomePage extends StatelessWidget {
  final String title;

  MyHomePage({this.title});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Choose your theme:',
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                /// //////////////////////////////////////////////////////
                /// Change theme & rebuild to show it using these buttons 
                ElevatedButton(
                    onPressed: () => MyApp.of(context).changeTheme(ThemeMode.light),
                    child: Text('Light')),
                ElevatedButton(
                    onPressed: () => MyApp.of(context).changeTheme(ThemeMode.dark),
                    child: Text('Dark')),
                /// //////////////////////////////////////////////////////
              ],
            ),
          ],
        ),
      ),
    );
  }
}

为了 return 主题控制回到设备的黑暗模式设置,创建第三个按钮来调用将 themeMode: 设置为 ThemeMode.system:

  • MyApp.of(context).changeTheme(ThemeMode.system)

运行 此方法会将应用主题的控制委托回设备当前使用的任何深色模式设置。

代码:完整的复制粘贴代码available in this gist.

派对有点晚了,您可以在没有任何第三方状态管理的情况下使用内置 ValueNotifier.This 方法实现它,允许您从应用程序的任何部分更改整个应用程序的主题。

这是dartpad demo

完整的代码示例

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

final darkNotifier = ValueNotifier<bool>(false);

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<bool>(
        valueListenable: darkNotifier,
        builder: (BuildContext context, bool isDark, Widget? child) {
          return MaterialApp(
            title: 'Flutter Demo',
            themeMode: isDark ? ThemeMode.dark : ThemeMode.light,
            theme: ThemeData(primaryColor: Colors.blue),
            darkTheme: ThemeData.dark(),
            home: MyHomePage(
              title: 'Homepage',
            ),
          );
        });
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  void dispose() {
    // TODO: implement dispose
    darkNotifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    bool isDark = darkNotifier.value;
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              _darkNotifier.value ? 'DarkMode' : 'LightMode',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          isDark = !isDark;
          darkNotifier.value = isDark;
        },
        tooltip: 'Increment',
        child: Icon(isDark ? Icons.wb_sunny_outlined : Icons.bubble_chart),
      ),
    );
  }
}

用于自定义 dark 主题

根据您的需要使用 darkTheme: ThemeData( use theme properties you need in dark mode)

描述:

如果 dark 模式在你的系统中被 selected 那么 flutter 使用 darkTheme 属性 of MaterialApp 并且如果 light 是 select ed 然后 flutter 使用 theme 属性 of MaterialApp,下面的代码显示当你 select (在你的手机中尝试)你的系统中的 dark 选项然后你的应用程序将显示 scaffoldBackgroundColor: Colors.red 如果您 select light 那么它将显示 scaffoldBackgroundColor: Colors.amber

@override
Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      darkTheme: ThemeData(brightness: Brightness.dark, scaffoldBackgroundColor: Colors.red),
      theme: ThemeData(
        scaffoldBackgroundColor: Colors.amber,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }

完整代码

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      darkTheme: ThemeData(brightness: Brightness.dark, scaffoldBackgroundColor: Colors.red),
      // themeMode: ThemeMode.dark,
      theme: ThemeData(
        scaffoldBackgroundColor: Colors.amber,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    // print("brightness ${ColorScheme.}")
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'increment',
              style: Theme.of(context).textTheme.headline4,
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

我从 ITnext 找到了一个非常好的 approach,它不需要第三方包(shared_preferences 或 hive 除外)。这里有一个简短的总结(没有导入和切换器):

// this makes all variables available globally
library config.globals;

// initialize the theme model once
ThemeModel currentTheme = ThemeModel();
// also declare the box
Box? box;

config.dart

class ThemeModel with ChangeNotifier {
  // initialize the standard theme here, possible with an elvis to check for the brightness
  static bool _isDark = false;
  // set a getter just for a more clean approach
  bool get isDark => _isDark;

  ThemeModel() {
    // check for a stored value on initialization
    if(box!.containsKey("currentTheme")) {
      _isDark = box!.get("currentTheme");
    } else {
      // if there is no value, apply the standard theme
      box!.put("currentTheme", _isDark);
    }
  }

  ThemeMode currentTheme() {
    return _isDark ? ThemeMode.dark : ThemeMode.light;
  }

  void switchTheme() {
    // switches the theme by reversing the boolean
    _isDark = !_isDark;
    // storing the new value
    box!.put("currentTheme", _isDark);
    // notifies all listeners attached to the theme model
    notifyListeners();
  }

}

theme_model.dart

void main() async {
  // waits for the hive init before running the app
  box = await Hive.openBox("theme");
  runApp(YourApp());
}

class YourApp extends StatefulWidget {
  @override
  _YourAppState createState() => _YourAppState();
}

class _YourAppState extends State<YourApp> {

  @override
  void initState() {
    super.initState();
    // we are setting a listener to the currentTheme, 
    // so it gets notified once we toggle it
    currentTheme.addListener(() {
      setState((){});
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Your title',
      theme: ThemeData().light,
      darkTheme: ThemeData().dark,
      // it will always listen to changes made to currentTheme
      themeMode: currentTheme.currentTheme(),
      home: HomePage(),
    );
  }
}

main.dart

class HomePage extends StatelessWidget {    
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: <Widget>[
          Switch(
            // looking for the current value and sets the switch state
            value: currentTheme.isDark,
            onChanged: (value) {
              setState(() {
                // we then set the state to the new current theme
                currentTheme.switchTheme();
              });
            },
          ),
          // this is just a text next to the switch stating the current theme
          Text("${currentTheme.currentTheme().toString().split(".")[1]} mode"),
        ],
      );
    );
  }
}

homepage.dart

如果您想获得用户 ui 的偏好设置,您可以将默认值设置为 ThemeData.system。您必须调整代码以关注当前亮度,然后根据它的状态设置主题。之后它使用一个开关在暗模式和亮模式之间切换。

Example gif

下面是将主题浅色更改为深色的简单示例

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:theme_mode_switch/notify.dart';
    
    void main() {
      runApp(
          ChangeNotifierProvider(create: (context) => DarkMode(), child: MyApp()));
    }
    
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final thmode = Provider.of<DarkMode>(context); ///accessing the variable of provider class
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Dark Mode',
          theme: ThemeData(
            ///here the value of darmode var is updationg by switching
            brightness: thmode.darkMode ? Brightness.dark : Brightness.light,
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {      
        final thmode = Provider.of<DarkMode>(context);
        return Scaffold(
            appBar: AppBar(
              title: Text('Dark Mode'),
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(thmode.darkMode ? 'Dark' :'Light'),
                  CupertinoSwitch(
                    value: thmode.darkMode,
                    onChanged: (bool val) {
                      thmode.changemode();
                    },
                  ),
                ],
              ),
            ));
      }
    }


class DarkMode with ChangeNotifier {
  bool darkMode = true; ///by default it is true
  ///made a method which will execute while switching
  changemode() {
    darkMode = !darkMode;
    notifyListeners(); ///notify the value or update the widget value
  }
}

使用 get 软件包

比您想象的要容易得多
return GetMaterialApp(
  themeMode: lightOrDark?ThemeMode.light:ThemeMode.dark,
  ...
);

多个 Flutter 主题示例(浅色和深色主题)

  1. 在 .yaml 文件中添加提供程序

  2. 像这样声明 runApp 方法

runApp(ChangeNotifierProvider( create: (context) => ThemeState(), child: MyApp(), ));

  1. ChangeNotitifer
  2. 创建 ThemeState class 和 extend
    import 'package:flutter/material.dart';

    enum ThemeType { DARK, LIGHT }
    
    class ThemeState extends ChangeNotifier {
      bool _isDarkTheme = false;
    
      ThemeState() {
        getTheme().then((type) {
          _isDarkTheme = type == ThemeType.DARK;
          notifyListeners();
        });
      }
      ThemeType get theme => _isDarkTheme ? ThemeType.DARK : ThemeType.LIGHT;
      set theme(ThemeType type) => setTheme(type);
    
      void setTheme(ThemeType type) async {
        _isDarkTheme = type == ThemeType.DARK;
        notifyListeners();
      }
    
      Future<ThemeType> getTheme() async {
        return _isDarkTheme ? ThemeType.DARK : ThemeType.LIGHT;
      }
    }
  1. 在 MyApp 中 class 在 MaterialApp 中像这样声明它
    theme: Provider.of<ThemeState>(context).theme == ThemeType.DARK
                ? ThemeData(
                    // Define the default brightness and colors.
                    brightness: Brightness.dark,
                    primaryColor: Colors.lightBlue[800],
                    // Define the default font family.
                    fontFamily: 'Georgia',
                    // Define the default `TextTheme`. Use this to specify the default
                    // text styling for headlines, titles, bodies of text, and more.
                    textTheme: const TextTheme(
                      headline1:
                          TextStyle(fontSize: 32.0, fontWeight: FontWeight.bold),
                      headline6:
                          TextStyle(fontSize: 16.0, fontStyle: FontStyle.italic),
                      bodyText2: TextStyle(fontSize: 10.0, fontFamily: 'Hind'),
                    ),
                  )
                : ThemeData(
                    // Define the default brightness and colors.
                    brightness: Brightness.light,
                    primaryColor: Colors.lightGreen[300],
                    // Define the default font family.
                    fontFamily: 'Georgia',
                    // Define the default `TextTheme`. Use this to specify the default
                    // text styling for headlines, titles, bodies of text, and more.
                    textTheme: const TextTheme(
                      headline1:
                          TextStyle(fontSize: 32.0, fontWeight: FontWeight.normal),
                      headline6:
                          TextStyle(fontSize: 16.0, fontStyle: FontStyle.italic),
                      bodyText2: TextStyle(fontSize: 10.0, fontFamily: 'Hind'),
                    ),
                  ),