Flutter深色模式适配的实现

 更新时间:2021年4月4日 15:01  点击:1895

一、简介

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

二、环境介绍

1. Flutter: 2.0.3
2. Dart: 2.12.0
3. provider: 5.0.0
状态管理,用于运行时切换主题
4. shared_preferences: 2.0.5
数据持久化,用于保存当前选中的主题,以便下次启动时读取使用用户选择的主题

environment:
 sdk: ">=2.12.0 <3.0.0"

dependencies:
 flutter:
 sdk: flutter

 # 忽略了一些依赖...

 # shared_preferences https://pub.flutter-io.cn/packages/shared_preferences
 shared_preferences: ^2.0.5
 # 全局状态管理 https://github.com/rrousselGit/provider/blob/master/resources/translations/zh-CN/README.md
 provider: ^5.0.0

三、主题

1. ThemeData

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, // 导航边栏主题
 // ...
 })

2. main.dart or MaterialApp

theme为默认主题,darkTheme为深色主题,themeMode为当前使用哪个主题,可选值system、light、dark,只有在th``eme与darkTheme都设置的时候才会生效,我们的theme与darkTheme都直接使用ThemeData对象,给他指定了brightness,而不是使用这样感觉可以方便修改样式,当然也可以抽出来封装一下,我这没有去处理。

MaterialApp(
 theme: ThemeData(
 brightness: Brightness.light,
 // scaffoldBackgroundColor: Color(0xFFF5F5F9),
 ),
 darkTheme: ThemeData(
 brightness: Brightness.dark,
 // scaffoldBackgroundColor: Color(0xFFF5F5F9),
 ),
 themeMode: context.watch<ThemeModel>().theme
);

四、全局配置

全局配置是在MaterialApp加载之前进行一写初始化操作,参考了《Flutter实战》电子书,Flutter当中SharedPreferences是异步初始化,还有Dio网络请求的缓存也需要提前初始化,我们这里SharedPreferences加载完之后在进行之后的操作,SpUtils中的SharedPreferences使用的Global全局配置中的静态属性。

1. Global

class Global {
 static late SharedPreferences prefs;

 static ThemeMode theme = ThemeMode.light;

 // 是否为release版
 static bool get isRelease => bool.fromEnvironment("dart.vm.product");

 //初始化全局信息,会在APP启动时执行
 static Future init() async {
 WidgetsFlutterBinding.ensureInitialized();
 prefs = await SharedPreferences.getInstance();

 // 当前本地存储的主题
 String themeValue = await SpUtils.instance.getStorage(SpConstants.skin);
 theme = themeStringToThemeMode(themeValue);

 //初始化网络请求相关配置
 HttpManager();
 }
}

2. main.dart

// Global加载完成后掉用runApp
Global.init().then((e) => runApp());

3. themeStringToThemeMode()

字符串转ThemeMode

ThemeMode themeStringToThemeMode(String themeValue){
 ThemeMode theme = ThemeMode.light;
 switch (themeValue) {
 case "light":
  theme = ThemeMode.light;
  break;
 case "dark":
  theme = ThemeMode.dark;
  break;
 case "system":
  theme = ThemeMode.system;
  break;
 }
 return theme;
}

五、使用状态管理(provider)切换主题

> 此处大坑,处处劝退,感谢Flutter provider劝退经历这篇文章

1. 构建主题Model

class ThemeModel extends ChangeNotifier {

 // 获取当前主题,如果为设置主题,则默认使用浅色模式
 ThemeMode get theme => Global.theme;

 // 主题改变后,通知其依赖项,新主题会立即生效
 set theme(ThemeMode themeMode) {
 if (themeMode != theme) {
  Global.theme = themeMode;
  notifyListeners();
 }
 }
}

2. main.dart(监听值变化)

此处为main.dart文件的完整代码,下面有关provider的一些使用方式可能与网上很多文章不一样的,但是这都是官网文档的最新推荐使用方式。读取当前provider中存储的主题context.watch<ThemeModel>().theme

void main() {
 //顶部状态栏透明
 SystemChrome.setSystemUIOverlayStyle(
  SystemUiOverlayStyle(statusBarColor: Colors.transparent));
 Global.init().then((e) => runApp(
  MultiProvider(
   providers: [ListenableProvider<ThemeModel>(create: (_) => ThemeModel())],
   builder: (context, child) {
    return WanAndroid();
   }),
  ));
}

class WanAndroid extends StatelessWidget {
 // This widget is the root of your application.
 @override
 Widget build(BuildContext context) {
 return MaterialApp(
  initialRoute: '/',
  theme: ThemeData(
  brightness: Brightness.light,
  // scaffoldBackgroundColor: Color(0xFFF5F5F9),
  ),
  darkTheme: ThemeData(
  brightness: Brightness.dark,
  // scaffoldBackgroundColor: Color(0xFFF5F5F9),
  ),
  themeMode: context.watch<ThemeModel>().theme,
  routes: {
  '/': (context) => SplashPage(),
  '/index': (context) => IndexPage(),
  '/login': (context) => LoginPage(),
  '/setting': (context) => SettingPage(),
  },
  title: '玩Android-Flutter版',
 );
 }
}

3. 切换主题

修改provider中保存的值即可。

// themeStringToThemeMode方法代码在上面有写
context.read<ThemeModel>().theme = themeStringToThemeMode(value);

六、源码

- 源码:github.com/sdwfqin/flutter_wanandroid

到此这篇关于Flutter深色模式适配的实现的文章就介绍到这了,更多相关Flutter深色模式适配内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • Flutter悬浮按钮FloatingActionButton使用详解

    本文主要介绍了Flutter悬浮按钮FloatingActionButton使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-07-12
  • Flutter 开发一个登录页面

    登录页面在 App 开发中非常常见,本篇借登录页面的开发介绍了文本框 TextField组件的使用,同时使用文本框的装饰属性实现了个性化文本框设置。...2021-06-05
  • Flutter 底部弹窗ModelBottomSheet的使用示例

    在实际开发过程中,经常会用到底部弹窗来进行快捷操作,例如选择一个选项,选择下一步操作等等。在 Flutter 中提供了一个 showModelBottomSheet 方法用于弹出底部弹窗,本篇介绍如何使用底部弹窗。...2021-06-07
  • Flutter 如何封装文本输入框组件

    在实际开发过程中,往往开始是完成功能层面的开发,然而再考虑组件封装和代码优化。当然,组件封装越早做越好,因为这样会提高整个团队开发的规范性和效率。本文将介绍如何封装一个文本输入框组件...2021-06-05
  • Flutter项目在 iOS14 启动崩溃的解决方法

    这篇文章主要介绍了Flutter项目在 iOS14 启动崩溃的解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-09-24
  • flutter实现点击事件

    这篇文章主要介绍了flutter实现点击事件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-26
  • flutter的环境安装配置问题及解决方法

    Flutter是Google推出的基于Dart语言开发的跨平台开源UI框架,旨在统一纷纷扰扰的跨平台开发框架,在UI层面上多端共用一套Dart代码来实现多平台适配开发,这篇文章主要介绍了flutter的环境安装配置问题,需要的朋友可以参考下...2020-06-09
  • 详解Flutter 调用 Android Native 的方法

    这篇文章主要介绍了详解Flutter 调用 Android Native 的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-25
  • Flutter开发中的路由参数处理

    在实际开发中,我们经常会需要在页面跳转的时候携带路由参数,典型的例子就是从列表到详情页的时候,需要携带详情的 id,以便详情页获取对应的数据。同时,有些时候还需要返回时携带参数返回上一级,以便上级页面根据返回结果更新。本篇将介绍这两种情形的实现。...2021-06-18
  • 用Flutter做桌上弹球(绘图(Canvas&CustomPaint)API)

    这篇文章主要介绍了用Flutter做桌上弹球 聊聊绘图(Canvas&CustomPaint)API,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-07-31
  • Flutter Android应用启动白屏的解决方案

    任何一个app基本都会设计一个启动页,今天我们就来看看怎么在flutter项目中设置启动页,这篇文章主要给大家介绍了关于Flutter Android应用启动白屏解决的相关资料,需要的朋友可以参考下...2021-11-11
  • Flutter实现局部刷新

    这篇文章主要为大家详细介绍了Flutter实现局部刷新,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-07-14
  • Flutter路由fluro引入配置和使用的具体方法

    Flutter本身提供了路由机制,本文主要介绍了Flutter fluro配置使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-08
  • Canonical通过Flutter启用Linux桌面应用程序(推荐)

    这篇文章主要介绍了Canonical通过Flutter启用Linux桌面应用程序,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-07-10
  • 如何在Flutter中嵌套Android布局

    通常Flutter与Android页面交互是各自独占整个手机屏幕,但有些情况下无法满足需求,有些时候Flutter中没有提供相关插件或者插件不满足需求,这时候就需要开发者自定义插件,开发者可以参考本文中的方法去进行自定义。...2021-06-07
  • Flutter中如何使用WillPopScope的示例代码

    这篇文章主要介绍了Flutter中如何使用WillPopScope,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-05-14
  • Flutter深色模式适配的实现

    这篇文章主要介绍了Flutter深色模式适配的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-04
  • Android如何在原生App中嵌入Flutter

    这篇文章主要介绍了Android如何在原生App中嵌入Flutter,帮助大家更好的理解和学习Android开发,感兴趣的朋友可以了解下...2021-03-13
  • Flutter仿钉钉考勤日历的示例代码

    这篇文章主要介绍了Flutter仿钉钉考勤日历的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-23
  • Flutter软键盘的原理浅析

    大家应该都知道目前Flutter官方是没有自定义键盘的解决方案,下面这篇文章主要给大家介绍了关于Flutter软键盘原理的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下...2021-10-08