Flutter

flutter适配iOS、Android的深色模式

2020-03-19  本文已影响0人  xmb

参考文章:
https://www.jianshu.com/p/76539f98b146
https://www.jianshu.com/p/7b253699dbc5

1、查看当前的黑暗模式状态

final Brightness brightnessValue = MediaQuery.of(context).platformBrightness;
bool isDark = brightnessValue == Brightness.dark;

代码如下:
dark_mode.dart

/// 深色模式

class DarkMode {
  // 判断当前是否为深色模式 true:深色  false:浅色
  static bool isDark({BuildContext context}) {
    // return false - 完全屏蔽深色模式功能,不开启深色模式
    return false;

//    if (getDarkModeStatus() == DarkModeStatus.dark) {
//      // 深色
////      LogUtils.d('模式', '深色');
//      return true;
//    } else if (getDarkModeStatus() == DarkModeStatus.light) {
//      // 浅色
////      LogUtils.d('模式', '浅色');
//      return false;
//    } else {
//      // 跟随系统
////      LogUtils.d('模式', '跟随系统');
//      if (context != null) {
//        return MediaQuery.of(context).platformBrightness == Brightness.dark;
//      } else {
//        return WidgetsBinding.instance.window.platformBrightness == Brightness.dark;
//      }
//    }
  }

  // 获取深色模式状态
  static DarkModeStatus getDarkModeStatus() {
    int status = App.getInstance().getInt(SPKeyConst.darkModeKey);
    if (status == null) {
      App.getInstance().setInt(SPKeyConst.darkModeKey, 0);
    }

    if (status == 1) {
      return DarkModeStatus.dark;
    } else if (status == 2) {
      return DarkModeStatus.light;
    } else {
      return DarkModeStatus.followSystem;
    }
  }
}

dark_mode_provider.dart

class DarkModeProvider extends ChangeNotifier {
  // 同步深色模式
  void syncTheme() {
    int theme = App.getInstance().getInt(SPKeyConst.darkModeKey);
    if (theme != null && theme != 0) {
      notifyListeners();
    }
  }

  // 设置深色模式
  void setTheme(DarkModeStatus status) {
    if (status == DarkModeStatus.followSystem) {
      // 设置-跟随系统
      App.getInstance().setInt(SPKeyConst.darkModeKey, 0);
    } else if (status == DarkModeStatus.dark) {
      // 设置深色
      App.getInstance().setInt(SPKeyConst.darkModeKey, 1);
    } else if (status == DarkModeStatus.light) {
      // 设置浅色
      App.getInstance().setInt(SPKeyConst.darkModeKey, 2);
    }

    notifyListeners();
  }

  // 主题样式
  ThemeData getTheme({bool isDark = false}) {
    int theme = App.getInstance().getInt(SPKeyConst.darkModeKey);
    if (theme == null) {
      theme = 0;
    }
    String themeStr = theme.toString();
    switch (themeStr) {
      case "1":
        isDark = true;
        break;
      case "2":
        isDark = false;
        break;
      default:
        break;
    }

    return ThemeData(
      // 深色/浅色
      brightness: isDark ? Brightness.dark : Brightness.light,
      // 主题色
      primarySwatch: Colors.blue,
      // 页面背景色
      scaffoldBackgroundColor: isDark ? R.dark_scaffold_bg_color : R.color_white_F6F6F6,
      // 背景色
      backgroundColor: isDark ? R.dark_scaffold_bg_color : R.color_white,
      // 主要用于Material背景色
      canvasColor: isDark ? R.dark_bg_color : R.color_white,
      // Tab指示器颜色
      indicatorColor: isDark ? R.color_green_3CB71D : R.color_green_3CB71D,
      // 导航栏默认样式
      appBarTheme: AppBarTheme(
        elevation: 0,
        color: isDark ? R.dark_nav_bg_color : R.color_white,
        brightness: isDark ? Brightness.dark : Brightness.light,
        textTheme: TextTheme(
          headline6: TextStyle(
            fontSize: R.font_36,
            fontWeight: FontWeight.w500,
            color: isDark ? R.color_white : R.color_black_333333,
          ),
        ),
      ),
      // 文本样式
      textTheme: TextTheme(
          // text默认文字样式
          bodyText2: TextStyle(
            color: isDark ? R.color_white : R.color_black_333333,
          ),
          // TextField输入文字颜色
          subtitle1: TextStyle(
            color: isDark ? R.color_white : R.color_black_333333,
          ),
          // 小文字样式
          subtitle2: TextStyle(
            color: isDark ? R.dark_subtitle : R.color_grey_666666,
          ),
          // 说明描述
          caption: TextStyle(
            color: isDark ? R.dark_caption : R.color_grey_999999,
          )),
      // 分割线样式
      dividerTheme: DividerThemeData(
        color: isDark ? R.dark_line : R.color_grey_EEE,
        space: 0.6,
        thickness: 0.6,
      ),
    );
  }

  /// 项目通用适配样式 ============================================

  // 页面背景色: R.color_white_F6F6F6 / R.dark_scaffold_bg_color
  static Color scaffoldBackgroundColor(BuildContext context) {
    return Theme.of(context).scaffoldBackgroundColor;
  }

  // widget背景色: R.color_white / R.dark_bg_color
  static Color canvasColor(BuildContext context) {
    return Theme.of(context).canvasColor;
  }

  // 默认文本颜色: R.color_black_333333 / R.color_white
  static Color textColor(BuildContext context) {
    return Theme.of(context).textTheme.headline6.color;
  }

  // 默认返回按钮背景色: R.color_black_333333 / R.color_white
  static Color navBackColor(BuildContext context) {
    return Theme.of(context).textTheme.headline6.color;
  }

  // 默认导航栏文本样式
  static appBarTitleStyle(BuildContext context) {
    return Theme.of(context).appBarTheme.textTheme.headline6;
  }

  // 灰色文本颜色 666666
  static gray666666TextColor(BuildContext context) {
    return Theme.of(context).textTheme.subtitle2.color;
  }

  // 灰色文本颜色 999999
  static gray999999TextColor(BuildContext context) {
    return Theme.of(context).textTheme.caption.color;
  }
}

main.dartmain()

runApp(ChangeNotifierProvider<DarkModeProvider>(
    create: (context) => DarkModeProvider(),
    child: MyApp(),
  ));

main.dartMyApp

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      // 由于SpUtil未初始化,所以MaterialApp获取的为默认主题配置,这里同步一下。
      Provider.of<DarkModeProvider>(context, listen: false).syncTheme();
    });
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

MyApp

  // 监听系统显示模式改变
  @override
  void didChangePlatformBrightness() {
    final Brightness brightness = WidgetsBinding.instance.window.platformBrightness;
    if (brightness == Brightness.dark) {
      LogUtils.d('tag', '当前系统显示模式:深色模式');
    } else {
      LogUtils.d('tag', '当前系统显示模式:浅色模式');
    }
    setState(() {});
  }

@override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: providers,
      child: Consumer2<DarkModeProvider,SettingsProvider>(
        builder:  (_, darkModeProvider, settingsProvider, __) {
          return PlatformApp(
            theme: darkModeProvider.getTheme(),
            // 是否开启深色模式
            darkTheme: darkModeProvider.getTheme(isDark: DarkMode.isDark()),
            ...
            ...
          );
        },
      ),
    );
  }

设置页

  // 进入深色模式
  void gotoDarkModeSetting() {
    NavigatorRoute.push(
      context,
      DarkModeSettingPage(),
      pageName: RouteName.darkModeSettingPageName,
    );
  }

  // 获取状态
  String getDarkModeStatus() {
    int status = App.getInstance().getInt(SPKeyConst.darkModeKey) ?? 0;
    if (status == 1) {
      return '深色';
    } else if (status == 2) {
      return '浅色';
    } else {
      return '跟随系统';
    }
  }

深色模式设置页

/// 深色模式

// 深色模式状态
enum DarkModeStatus {
  followSystem, // 跟随系统0
  dark, // 深色1
  light, // 浅色2
}

class DarkModeSettingPage extends StatefulWidget {
  @override
  _DarkModeSettingPageState createState() => _DarkModeSettingPageState();
}

class _DarkModeSettingPageState extends State<DarkModeSettingPage> {
  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  // 设置0跟随系统、1深色、2浅色
  void setDarkModeAction(BuildContext context, DarkModeStatus status) {
    Provider.of<DarkModeProvider>(context, listen: false).setTheme(status);

    if (status == DarkModeStatus.followSystem) {
      // 设置-跟随系统
      App.getInstance().setInt(SPKeyConst.darkModeKey, 0);
    } else if (status == DarkModeStatus.dark) {
      // 设置深色
      App.getInstance().setInt(SPKeyConst.darkModeKey, 1);
    } else if (status == DarkModeStatus.light) {
      // 设置浅色
      App.getInstance().setInt(SPKeyConst.darkModeKey, 2);
    }

    setState(() {});
  }

  // 获取状态
  DarkModeStatus getDarkModeStatus() {
    int status = App.getInstance().getInt(SPKeyConst.darkModeKey) ?? 0;
    if (status == 1) {
      return DarkModeStatus.dark;
    } else if (status == 2) {
      return DarkModeStatus.light;
    } else {
      return DarkModeStatus.followSystem;
    }
  }

  @override
  Widget build(BuildContext context) {
    return PlatformScaffold(
      backgroundColor: Theme.of(context).scaffoldBackgroundColor,
      appBar: PlatformAppBar(
        preferredSizeWidget: AppBarWidget(
          elevation: 0,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              GestureDetector(
                onTap: () {
                  Navigator.of(context).pop();
                },
                child: Container(
                  padding: EdgeInsets.only(right: 20),
                  color: R.color_transparent,
                  width: 64.0,
                  height: 44.0,
                  child: Image.asset(
                    'images/base/black_left_back_icon.png',
                    width: 8.5,
                    height: 14,
                    color: DarkModeProvider.navBackColor(context),
                  ),
                ),
              ),
              Expanded(
                child: Center(
                  child: Text(
                    '深色模式',
                    style: DarkModeProvider.appBarTitleStyle(context),
                    textAlign: TextAlign.center,
                  ),
                ),
              ),
              SizedBox(
                width: 64,
              ),
            ],
          ),
        ),
      ),
      body: Container(
        child: ListView(
          children: <Widget>[
            GestureDetector(
              onTap: () {
                setDarkModeAction(context, DarkModeStatus.followSystem);
              },
              behavior: HitTestBehavior.opaque,
              child: Container(
                padding: EdgeInsets.symmetric(horizontal: 15),
                color: Theme.of(context).canvasColor,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Container(
                      width: 100,
                      padding: EdgeInsets.symmetric(vertical: 13.5),
                      child: Text(
                        '跟随系统',
                        style: TextStyle(
                          fontSize: R.font_32,
                        ),
                      ),
                    ),
                    Offstage(
                      offstage: getDarkModeStatus() != DarkModeStatus.followSystem,
                      child: Image.asset('images/base/check_mark.png'),
                    ),
                  ],
                ),
              ),
            ),
            Divider(
              height: 1,
            ),
            GestureDetector(
                onTap: () {
                  // 深色
                  setDarkModeAction(context, DarkModeStatus.dark);
                },
                behavior: HitTestBehavior.opaque,
                child: Container(
                  padding: EdgeInsets.symmetric(horizontal: 15),
                  color: Theme.of(context).canvasColor,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Container(
                        width: 100,
                        padding: EdgeInsets.symmetric(vertical: 13.5),
                        child: Text(
                          '深色',
                          style: TextStyle(
                            fontSize: R.font_32,
                          ),
                        ),
                      ),
                      Offstage(
                        offstage: getDarkModeStatus() != DarkModeStatus.dark,
                        child: Image.asset('images/base/check_mark.png'),
                      ),
                    ],
                  ),
                )),
            Divider(
              height: 1,
            ),
            GestureDetector(
              onTap: () {
                // 浅色
                setDarkModeAction(context, DarkModeStatus.light);
              },
              behavior: HitTestBehavior.opaque,
              child: Container(
                padding: EdgeInsets.symmetric(horizontal: 15),
                color: Theme.of(context).canvasColor,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Container(
                      width: 100,
                      padding: EdgeInsets.symmetric(vertical: 13.5),
                      child: Text(
                        '浅色',
                        style: TextStyle(
                          fontSize: R.font_32,
                        ),
                      ),
                    ),
                    Offstage(
                      offstage: getDarkModeStatus() != DarkModeStatus.light,
                      child: Image.asset('images/base/check_mark.png'),
                    ),
                  ],
                ),
              ),
            ),
            Divider(
//              height: 1,
                ),
          ],
        ),
      ),
    );
  }
}

适配注意事项:

  1. 导航栏返回按钮
    image添加 color: DarkModeProvider.navBackColor(context)

  2. 导航栏背景色
    AppBarWidget中的以下3行代码去掉

backgroundColor: R.color_white,
appBarColor: R.color_white,
brightness: Brightness.light,

导航栏的返回按钮 或 导航栏右侧的按钮,添加 color: DarkModeProvider.navBackColor(context)
中间的居中标题样式,style替换为 style: DarkModeProvider.appBarTitleStyle(context)

  1. 背景色
    页面背景色:
    PlatformScaffold中的 backgroundColor: Colors.white,
    backgroundColor: R.color_white_F6F6F6,
    替换为 backgroundColor: Theme.of(context).scaffoldBackgroundColor

widget白色背景:
Colors.whiteR.color_white 替换为 DarkModeProvider.canvasColor(context)

  1. 文本颜色
    黑色文本颜色 R.color_black_333333 去掉,文本颜色会自动改变

注意这里导航栏里的Text文本颜色R.color_black_333333在这里不适用,不要去掉,
而是改为DarkModeProvider.textColor(context)

灰色字体颜色
R.color_grey_666666 替换为 DarkModeProvider.gray666666TextColor(context)
R.color_grey_999999 替换为 DarkModeProvider.gray999999TextColor(context)

  1. 分割线
    Divider的color去掉,颜色自动改变
上一篇下一篇

猜你喜欢

热点阅读