一、简介
Flutter的深色模式以及跟随系统设置比较简单,我感觉需要注意的是开发过程中尽量使用Theme中的颜色与样式,开发过程中遇到的比较大的坑就是provider的一些问题,可能是因为我用的版本新一些,网上找了很多文章,总会遇到一些问题。本文的深色模式适配是通过修改themeMode来实现的,供诸位有缘人参考。

二、环境介绍
- Flutter: 2.0.3 
- Dart: 2.12.0 
- provider: 5.0.0 - 状态管理,用于运行时切换主题 
- shared_preferences: 2.0.5 
数据持久化,用于保存当前选中的主题,以便下次启动时读取使用用户选择的主题
| 1 | environment: | 
三、主题
- ThemeData - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50- factory ThemeData({ 
 Brightness brightness, // 应用主题亮度,可选(dark、light)
 VisualDensity visualDensity, // 视觉密度
 MaterialColor primarySwatch, // 主要样式,设置primaryColor后该背景色会被覆盖
 Color primaryColor, // 主要部分背景颜色(导航和tabBar等)
 Brightness primaryColorBrightness, // primaryColor的亮度
 Color primaryColorLight, // primaryColor的浅色版
 Color primaryColorDark, // primaryColor的深色版
 Color accentColor, // 前景色(文本,按钮等)
 Brightness accentColorBrightness, // accentColor的亮度
 Color canvasColor, // MaterialType.canvas 的默认颜色
 Color shadowColor, // 阴影颜色
 Color scaffoldBackgroundColor, // Scaffold的背景颜色。典型Material应用程序或应用程序内页面的背景颜色
 Color bottomAppBarColor, // BottomAppBar的默认颜色
 Color cardColor, // Card的颜色
 Color dividerColor, // Divider和PopupMenuDivider的颜色,也用于ListTile之间、DataTable的行之间等。
 Color focusColor, // 突出颜色
 Color hoverColor, // hoverColor
 Color highlightColor, // 高亮颜色,选中在泼墨动画期间使用的突出显示颜色,或用于指示菜单中的项。
 Color splashColor, // 墨水飞溅的颜色。InkWell
 InteractiveInkFeatureFactory splashFactory, // 定义由InkWell和InkResponse反应产生的墨溅的外观。
 Color selectedRowColor, // 用于突出显示选定行的颜色。
 Color unselectedWidgetColor, // 用于处于非活动(但已启用)状态的小部件的颜色。例如,未选中的复选框。通常与accentColor形成对比。也看到disabledColor。
 Color disabledColor, // 禁用状态下部件的颜色,无论其当前状态如何。例如,一个禁用的复选框(可以选中或未选中)。
 Color buttonColor, // RaisedButton按钮中使用的Material 的默认填充颜色。
 ButtonThemeData buttonTheme, // 定义按钮部件的默认配置,
 ToggleButtonsThemeData toggleButtonsTheme, // 切换按钮的主题
 Color secondaryHeaderColor, // 选定行时PaginatedDataTable标题的颜色。
 Color textSelectionColor, // 文本框中文本选择的颜色,如TextField
 Color cursorColor, // 文本框中光标的颜色,如TextField
 Color textSelectionHandleColor, // 调整当前选定的文本部分的句柄的颜色。
 Color backgroundColor, // 与主色形成对比的颜色,例如用作进度条的剩余部分。
 Color dialogBackgroundColor, // Dialog元素的背景颜色
 Color indicatorColor, // 选项卡中选定的选项卡指示器的颜色。
 Color hintColor, // 用于提示文本或占位符文本的颜色,例如在TextField中。
 Color errorColor, // 用于输入验证错误的颜色,例如在TextField中
 Color toggleableActiveColor, // 用于突出显示Switch、Radio和Checkbox等可切换小部件的活动状态的颜色。
 String fontFamily, // 文本字体
 TextTheme textTheme, // 文本的颜色与卡片和画布的颜色形成对比。
 TextTheme primaryTextTheme, // 与primaryColor形成对比的文本主题
 TextTheme accentTextTheme, // 与accentColor形成对比的文本主题。
 InputDecorationTheme inputDecorationTheme, // 基于这个主题的 InputDecorator、TextField和TextFormField的默认InputDecoration值。
 TabBarTheme tabBarTheme, // 用于自定义选项卡栏指示器的大小、形状和颜色的主题。
 TooltipThemeData tooltipTheme, // tooltip主题
 CardTheme cardTheme, // Card的颜色和样式
 AppBarTheme appBarTheme, // appBar主题
 ColorScheme colorScheme, // 拥有13种颜色,可用于配置大多数组件的颜色。
 NavigationRailThemeData navigationRailTheme, // 导航边栏主题
 // ...
 })
- main.dart or MaterialApp 
theme为默认主题,darkTheme为深色主题,themeMode为当前使用哪个主题,可选值system、light、dark,只有在th``eme与darkTheme都设置的时候才会生效,我们的theme与darkTheme都直接使用ThemeData对象,给他指定了brightness,而不是使用这样感觉可以方便修改样式,当然也可以抽出来封装一下,我这没有去处理。
| 1 | MaterialApp( | 
四、全局配置
全局配置是在MaterialApp加载之前进行一写初始化操作,参考了《Flutter实战》电子书,Flutter当中SharedPreferences是异步初始化,还有Dio网络请求的缓存也需要提前初始化,我们这里SharedPreferences加载完之后在进行之后的操作,SpUtils中的SharedPreferences使用的Global全局配置中的静态属性。
- Global
| 1 | class Global { | 
- main.dart
| 1 | // Global加载完成后掉用runApp | 
- themeStringToThemeMode()
字符串转ThemeMode
| 1 | ThemeMode themeStringToThemeMode(String themeValue){ | 
五、使用状态管理(provider)切换主题
此处大坑,处处劝退,感谢Flutter provider劝退经历这篇文章
- 构建主题Model
| 1 | class ThemeModel extends ChangeNotifier { | 
- main.dart(监听值变化)
此处为main.dart文件的完整代码,下面有关provider的一些使用方式可能与网上很多文章不一样的,但是这都是官网文档的最新推荐使用方式。读取当前provider中存储的主题context.watch<ThemeModel>().theme
| 1 | void main() { | 
- 切换主题
修改provider中保存的值即可。
| 1 | // themeStringToThemeMode方法代码在上面有写 |