75

我想创建一个具有 2 个明暗模式主题的颤振应用程序,这些主题通过应用程序内的切换进行更改,默认主题是默认的 android 主题。
我需要将一些自定义颜色传递给其他小部件,我不想只配置材质主题。

  • 如何检测用户设备的默认主题?
  • 第二个问题是如何为整个应用程序提供主题?
  • 三是如何在运行时通过简单的切换来改变主题?
4

15 回答 15

103

使用材料应用程序

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();

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_modelproviderblocget来获得无缝体验。

于 2020-06-27T08:49:23.800 回答
50

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

输出 在此处输入图像描述

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

存储管理器.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 变量。

主题管理器.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 包装您的应用程序,然后使用消费者应用主题。通过这样做,每当您更改主题的值并调用通知侦听器小部件重建以同步更改。

主要.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'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

是 github 存储库的链接。

于 2020-09-18T11:12:41.777 回答
28

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

  • 总是暗模式
  • 设备/平台控制的暗模式
  • 应用程序控制,运行时可切换暗模式

始终黑暗模式

要仅在暗模式下运行您的应用程序:

  • MaterialApp,替换ThemeData(...)ThemeData.dark()
  • 重新启动您的应用程序。它现在将使用中定义的颜色在暗模式下运行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+(引入暗模式时)
  • 要让设备/平台设置主题,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 使用设备/平台主题设置
  • 在 Android 10+ 或 iOS 13+ 上使用上述设置,通过设备设置切换暗模式现在将在明暗模式之间切换您的应用。
  • 每当设备主题发生变化时,您的应用程序将立即反映所选的设备主题
  • 要以编程方式获取当前设备主题模式,我们可以检查设备亮度(Brightness.lightBrightness.dark),它对应于亮模式和暗模式。通过查询来做到这一点platformBrightnessMediaQuery.of(context).platformBrightness

应用程序控制的暗模式

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

如何重建 MaterialApp 小部件

  • 要从任何地方切换我们的应用程序主题,我们需要MaterialApp从应用程序的任何地方访问
  • 我们可以在没有任何包的情况下使用 just 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'),
    );
  }
}

之后 - 有状态

  • 在这里,我们MyApp StatelessWidget用 aStatefulWidget和它的互补State类替换了,_MyAppState
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.
  • 注意Type我们of()方法的返回:_MyAppState
  • 我们没有得到StatefulWidget,我们得到了它的State对象:_MyAppState
  • _MyAppState将保持我们ThemeMode设置的“状态”(在下一步中)。这是控制我们应用程序当前主题的内容。
  • 接下来在我们的_MyAppState课程中,我们将添加一个ThemeMode“状态”字段和一个更改主题并重建我们的应用程序的方法

_MyAppState

  • 下面是我们State修改的类:
    1. “状态”字段_themeMode
    2. MaterialApp themeMode:_themeMode使用状态字段值的arg
    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')),
                /// //////////////////////////////////////////////////////
              ],
            ),
          ],
        ),
      ),
    );
  }
}

更改主题按钮

要将主题控制返回到设备的暗模式设置,请创建第三个按钮以调用 setthemeMode:ThemeMode.system

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

运行此方法会将应用程序主题的控制权委托给设备当前使用的任何暗模式设置。

代码:此 gist 中提供了完整的复制粘贴代码。

于 2021-05-27T00:58:19.007 回答
22

让系统处理主题:

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

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

于 2020-10-03T15:35:43.143 回答
10
MaterialApp(
  theme: ThemeData.light(),
  /// theme: ThemeData.dark(),
)

在小部件树下,您可以简单地通过编写来访问 ThemeData Theme.of(context)。如果您想访问当前的 ThemeData 并为某些字段提供您自己的样式,您可以为一个实例执行以下操作:

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

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

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

于 2020-02-15T10:19:31.080 回答
10
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(),
      ),
    );
  }
}
于 2021-02-11T03:31:36.753 回答
8

截屏:

在此处输入图像描述


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

完整代码:

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'),
              ),
            ),
          ),
        );
      },
    );
  }
}
于 2020-10-03T16:09:38.400 回答
4

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

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(),
    );
  }
}
于 2021-04-29T20:11:34.523 回答
2
  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.
于 2021-02-11T03:36:08.497 回答
2

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

这是dartpad 演示

在此处输入图像描述

完整的代码示例

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),
      ),
    );
  }
}

于 2021-07-20T09:00:45.373 回答
2

对于自定义dark主题

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

描述:

如果dark在您的系统中选择了模式,则颤动使用darkTheme属性,MaterialApp 如果选择了光,则颤动使用theme属性MaterialApp,下面的代码显示当您dark在系统中选择(在手机中尝试)选项时,您的应用程序将显示scaffoldBackgroundColor: Colors.red,如果您选择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),
      ),
    );
  }
}
于 2021-09-28T12:44:23.520 回答
2

我从 ITnext 找到了一个非常好的方法,其中不需要第三方包(除了 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;

配置飞镖

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();
  }

}

主题模型.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(),
    );
  }
}

主要.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"),
        ],
      );
    );
  }
}

主页.dart

如果要获取用户 ui 首选项,可以将默认值设置为 ThemeData.system。您必须调整代码以查看当前亮度,然后根据其状态设置主题。之后,它使用开关在暗模式和亮模式之间切换。

示例 gif

于 2021-10-28T08:20:00.990 回答
1

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

一个 Flutter 插件,可以帮助你根据日出和日落自动更改应用程序的主题。只需指定要使用的明暗主题,一切就绪。您也可以使用自定义的日出和日落时间。

如何使用它?

  1. 在 pubspec.yaml 中添加最新版本的包
  2. 用 DayNightTheme 小部件包装 MaterialApp。
于 2021-01-19T09:32:05.393 回答
0

以下是将主题浅色更改为深色的简单示例在此处输入图像描述

    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
  }
}
于 2021-11-08T07:43:01.153 回答
0

使用get package比您想象的要容易得多

return GetMaterialApp(
  themeMode: lightOrDark?ThemeMode.light:ThemeMode.dark,
  ...
);
于 2022-01-17T07:47:29.260 回答