Flutter深色模式适配的实现

作者:张钦 时间:2023-01-22 12:41:03 

目录
  • 一、简介

  • 二、环境介绍

  • 三、主题

    • 1. ThemeData

    • 2. main.dart or MaterialApp

  • 四、全局配置

    • 1. Global

    • 2. main.dart

    • 3. themeStringToThemeMode()

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

    • 1. 构建主题Model

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

    • 3. 切换主题

  • 六、源码

    一、简介

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

    Flutter深色模式适配的实现

    二、环境介绍

    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

    来源:https://juejin.cn/post/6946850840728567816

    标签:Flutter,深色模式
    0
    投稿

    猜你喜欢

  • 基于Java利用static实现单例模式

    2021-12-20 06:07:32
  • c语言实现的几种常用排序算法

    2022-02-23 04:04:11
  • 使用webmagic实现爬虫程序示例分享

    2021-10-08 22:10:26
  • Android EditText限制输入整数和小数的位数的方法示例

    2022-12-23 05:15:30
  • Android 自定义View实现多节点进度条功能

    2022-05-04 17:13:37
  • C++类中的特殊成员函数示例详解

    2023-11-07 13:02:08
  • JavaFX实现简单日历效果

    2023-05-16 08:43:30
  • C#实现简单学生成绩管理系统

    2023-03-14 01:50:22
  • 浅谈java泛型的作用及其基本概念

    2022-08-10 07:53:47
  • Flutter源码分析之自定义控件(RenderBox)指南

    2022-09-08 21:17:28
  • java音乐播放器实现代码

    2022-08-29 08:41:22
  • Android Vibrator调节震动代码实例

    2022-07-06 04:56:46
  • spring中的注解事务演示和添加步骤详情

    2023-03-03 08:32:48
  • C#中Html.RenderPartial与Html.RenderAction的区别分析

    2022-03-17 01:27:59
  • Unity中的RegisterPlugins实用案例深入解析

    2022-04-02 10:14:41
  • c#通过ip获取地理信息

    2022-09-16 00:43:03
  • java注解结合aspectj AOP进行日志打印的操作

    2023-10-23 14:02:53
  • Unity3D实现打砖块游戏

    2021-11-13 11:29:44
  • c#定时器和global实现自动job示例

    2023-10-04 22:30:29
  • java数据库唯一id生成工具类

    2023-04-04 22:53:34
  • asp之家 软件编程 m.aspxhome.com