这些年,移动端UI的深色模式还是比较常见的,IOS在系统级别已经率先支持了,Flutter作为一款优秀的跨端UI框架,在处理深色模式上是比较简单的。

Flutter深色模式

Brightness

Flutter中有一个Brightness的概念,用来表示主题和颜色的亮暗模式。

enum Brightness {
  /// The color is dark and will require a light text color to achieve readable
  /// contrast.
  ///
  /// For example, the color might be dark grey, requiring white text.
  dark,

  /// The color is light and will require a dark text color to achieve readable
  /// contrast.
  ///
  /// For example, the color might be bright white, requiring black text.
  light,
}

Flutter针对主题也提供了封装:

factory ThemeData.light() => ThemeData(brightness: Brightness.light);

factory ThemeData.dark() => ThemeData(brightness: Brightness.dark);

访问方式如下:

final lightTheme = ThemeData.light();

final dartTheme = ThemeData.dark();

我们首先想一下,要实现一个切换深色主题的功能的步骤是什么?

  1. 设置页:进行浅色/深色模式切换,并进行持久化,以便app重启之后还是生效的;
  2. App:启动的时候获取持久化的浅色/深色模式,并应用到app的主题上;
  3. 切换时实时刷新主题的深浅模式;

1. 进行深浅色模式的切换

深色模式设置页面

这里使用SharedPreferences来进行持久化,代码比较简单:

import 'package:flutter/material.dart';
import 'package:flutter_system/constants/const_key_value.dart';
import 'package:flutter_system/theme/custom_themes.dart';
import 'package:flutter_system/utils/sp_utils.dart';
import 'package:provider/provider.dart';

/// 设置页
class SettingsPage extends StatefulWidget {
  @override
  _SettingsPageState createState() => _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
  bool _isDarkMode = false;

  @override
  void initState() {
    SpUtils.getBool(keyIsDarkMode, false).then((value) {
      setState(() {
        _isDarkMode = value;
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("设置页"),
        centerTitle: true,
      ),
      body: SafeArea(
          child: ListView(
        children: <Widget>[
          SwitchListTile(
            title: Text("深色模式"),
            value: _isDarkMode,
            onChanged: (newValue) {
              setState(() {
                SpUtils.saveBool(keyIsDarkMode, newValue);
                _isDarkMode = newValue;
                Provider.of<ThemesNotifier>(context)
                    .setCurrentTheme(newValue ? dartTheme : lightTheme);
              });
            },
            activeColor: Theme.of(context).accentColor,
          ),
        ],
      )),
    );
  }
}

App启动时获取持久化的深浅色模式

SpUtils.getBool(keyIsDarkMode, false).then((value) {
      Provider.of<ThemesNotifier>(context, listen: false)
          .setCurrentTheme(value ? dartTheme : lightTheme);
    });

深浅色模式改变时,实时刷新APP

从前面的两段代码可以看出,我们使用了Provider。

这里我们可以把Provider当做一个单例模式,一处改变,全局生效。

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    SpUtils.getBool(keyIsDarkMode, false).then((value) {
      Provider.of<ThemesNotifier>(context, listen: false)
          .setCurrentTheme(value ? dartTheme : lightTheme);
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final themeProvider = Provider.of<ThemesNotifier>(context);
    return MaterialApp(
      title: 'Flutter System',
      theme: themeProvider?.currentTheme ?? lightTheme,
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      routes: pageRouters,
      localizationsDelegates: [
        S.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: S.delegate.supportedLocales,
    );
  }
}

源码

https://github.com/jiangkang/flutter-system