Flutter 学习 之 主题设置 ThemeData

基于ThemeData 实现主题切换
1. 实现可以亮暗主题切换
2. 实现可以颜色主题的切换
3.当主题为白色的时候替换一个其他主颜色
4.当颜色为浅色时候需要做反色处理

演示效果

a5tnj-j7y0p.gif

一. 修改Main.dark 文件

    //多Provider 当前只用了一个 为以后打基础
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (context) => ThemeViewModel(),
        ),
      ],
      child: Consumer(
        builder: (context, themeProvider, Widget? child) {
          return MaterialApp(
            ///title android用来在多任务上显示昵称用的
            title: 'Flutter Theme Demo',
            //首页
            home: const MyHomePage(),
            //明亮的主题
            theme: themeProvider.getTheme(),
            //夜间模式
            darkTheme: themeProvider.getTheme(isDarkMode: true),
            //当前主题模式
            themeMode: themeProvider.getThemeMode(),
          );
        },
      ),
    );

二.定义 theme_provider.dart

  • 先拓展一下ThemeData 好通过SP保存
extension ThemeModeExitension on ThemeMode {
  String get value => ['System', 'Light', 'Dark'][index];
}
  • 创建类
class ThemeViewModel extends ChangeNotifier {
  ///主题模式 亮色 暗色 跟随系统
  ThemeMode? _themeMode;

  //亮色主题色
  late MaterialColor _themeColor;

  //暗色主题色
   final MaterialColor _themeDarkColor= ColorUtil.createMaterialColor(ColorConfig.darkBGColor);

  ThemeViewModel() {
    Color primaryColor=Colors.white; //设定一个初始颜色
    //如果由保存颜色则替换颜色
    String? color = CacheUtil().get(SPName.themeColor);
    if (color != null) {
      //把存储的#RRGGBB颜色转换十六进制的0xFF格式的
      primaryColor = ColorUtil.hexToColor(color);
    }
    _themeColor = ColorUtil.createMaterialColor(primaryColor);
  }



  get selectColor => isDark() ? _themeDarkColor : _themeColor;

  bool isDark() {
    //如果当前是跟随系统那么判定当前系统是不是暗色模式
    if (_themeMode == ThemeMode.system) {
      return SchedulerBinding.instance?.window.platformBrightness ==
          Brightness.dark;
    }
    return _themeMode == ThemeMode.dark;
  }

//获取当前主题模式
  ThemeMode getThemeMode() {
    String? themeModel = CacheUtil().get(SPName.themeMode);
    switch (themeModel) {
      case "Dark":
        _themeMode = ThemeMode.dark;
        break;
      case "System":
        _themeMode = ThemeMode.system;
        break;
      default:
        _themeMode = ThemeMode.light;
        break;
    }
    return _themeMode!;
  }
//获取保存的主题颜色
  Color getThemColor() {
    String? color = CacheUtil().get(SPName.themeColor);
    return _themeColor =
        ColorUtil.createMaterialColor(ColorUtil.hexToColor(color));
  }

///设置主题
  set them(ThemeMode themeMode) {
    CacheUtil().setString(SPName.themeMode, themeMode.value);
    _themeMode = themeMode;
    notifyListeners();
  }
///设置主题颜色
  set themeColor(Color color) {
    CacheUtil().setString(SPName.themeColor, ColorUtil.color2HEX(color));
    _themeColor = ColorUtil.createMaterialColor(color);
    them=ThemeMode.light;
  }
  /// 获取主题
  ThemeData getTheme({bool isDarkMode = false}) {
    var themeData = ThemeData(
        brightness: isDarkMode ? Brightness.dark : Brightness.light,
        //错误颜色
        errorColor: Colors.red,
        //主题色
        primaryColor: isDarkMode ? _themeDarkColor : _themeColor,
        //浅主题色
        primaryColorLight: isDarkMode ? _themeDarkColor[50] : _themeColor[50],
        //深主题色
        primaryColorDark: isDarkMode ? _themeDarkColor[700] : _themeColor[700],
        // Tab指示器的颜色 如果当前主题色是白色 那么指点杆的颜色指定为另一个
        indicatorColor: isDarkMode
            ? ColorConfig.darkBtnColor
            : ColorUtil.isWhiteColor(_themeColor)
                ? ColorConfig.lightBtnColor
                : _themeColor,
        // 页面背景色
        scaffoldBackgroundColor:
            isDarkMode ? ColorConfig.darkBGColor : ColorConfig.lightBGColor,
        //开关 单选和多选按钮选中效果
        toggleableActiveColor: isDarkMode
            ? ColorConfig.darkBtnColor
            : ColorUtil.isWhiteColor(_themeColor)
                ? ColorConfig.lightBtnColor
                : _themeColor,
        //progressIndicator 的背景颜色
        progressIndicatorTheme: ProgressIndicatorThemeData(
          color: isDarkMode
              ? ColorConfig.darkBtnColor
              : ColorUtil.isWhiteColor(_themeColor)
                  ? ColorConfig.lightBtnColor
                  : _themeColor,
        ),
        // textButtonTheme: TextButtonThemeData(style: ButtonStyle(MaterialStateProperty.all())),
        //Material 组件默认使用这个颜色 如果没配置则是一个蓝色
        primarySwatch: isDarkMode ? _themeDarkColor : _themeColor,
        //大部分的ListTile 控件都会用到 除了  ExpansionTile 他会覆盖一部分组件样式
        listTileTheme: ListTileThemeData(
          selectedTileColor: Colors.blue,
          iconColor: isDark()
              ? ColorConfig.darkBtnColor
              : ColorUtil.isLightColor(_themeColor)
                  ? ColorConfig.lightBtnColor
                  : _themeColor,
        ),
        //icon的主题设置
        iconTheme: IconThemeData(
            color: isDarkMode
                ? ColorConfig.darkBtnColor
                : ColorUtil.isWhiteColor(_themeColor)
                    ? ColorConfig.lightBtnColor
                    : _themeColor,
            size: 16),
        // textButtonTheme:TextButtonThemeData() ,
        //具体组件的颜色配置
        appBarTheme: AppBarTheme(
          backgroundColor: isDarkMode ? _themeDarkColor : _themeColor,
          elevation: 0,
          centerTitle: true,
          titleTextStyle: TextStyle(
              color: isDark()
                  ? ColorConfig.dartH1Color
                  : ColorUtil.isLightColor(_themeColor)
                      ? Colors.black
                      : Colors.white,
              fontSize: 20),
        ),
        //具体文字的颜色配置
        textTheme: TextTheme(
          //ListTitle中的Title用到
          subtitle1: TextStyle(
              color: isDarkMode
                  ? ColorConfig.dartH1Color
                  : ColorConfig.lightH1Color,
              fontSize: 18),
          subtitle2: TextStyle(
              color: isDark()
                  ? ColorConfig.dartH1Color
                  : ColorUtil.isLightColor(_themeColor)
                      ? Colors.black
                      : Colors.white,
              fontSize: 16),
          //用在非Material组件上的文字显示,
          bodyText1: TextStyle(
              color: isDarkMode
                  ? ColorConfig.dartH2Color
                  : ColorConfig.lightH2Color,
              fontSize: 16),
          //Material组件上的文字显示
          bodyText2: TextStyle(
              color: isDarkMode
                  ? ColorConfig.dartH2Color
                  : ColorConfig.lightH2Color,
              fontSize: 16),
          //ListTitle的副标题用这个颜色
          caption: TextStyle(
              color: isDarkMode
                  ? ColorConfig.dartH3Color
                  : ColorConfig.lightH3Color,
              fontSize: 14),

          button: TextStyle(
              color: isDarkMode
                  ? ColorConfig.darkBtnColor
                  : ColorUtil.isWhiteColor(_themeColor)?ColorConfig.lightBtnColor:_themeColor,
              fontSize: 16),
        ));
    return themeData;
  }
}

三.在另一界面的使用

  • 创建ViewModel
class HomePageViewModel extends BaseViewModel {
    //创建模式选择
  List> modelItem = [
    {"name": '跟随系统', "mode": ThemeMode.system},
    {"name": '白天模式', "mode": ThemeMode.light},
    {"name": '夜间模式', "mode": ThemeMode.dark},
  ];
  //创建主题颜色
  List colorList = [
    "#FFFFFF",
    "#843900",
    "#905d1d",
    "#b3424a",
    "#181d4b",
    "#d9d6c3",
    "#281f1d",
    "#ffeb3b",
    "#2A2C37",
    "#00FA9A",
    "#009ACD",
  ];
  //当前的模式
  ThemeMode? selectModel;
  //上下文
  BuildContext? context;
  //选择的颜色
  Color? selectColor;
  //themeViewModel
  var provider;
//切换模式
  void changeModel(value) {
    provider.them = value;
    selectModel = value;
    notifyListeners();
  }
//切换颜色
  void onChangeColor(String colorStr) {
    Color col = ColorUtil.hexToColor(colorStr);
    ThemeMode mode = ThemeMode.light;
    //如果切换的颜色是夜间模式 那么直接切换模式
    if (col == ColorConfig.darkBGColor) {
      mode = ThemeMode.dark;
      changeModel(mode);
    } else {
      provider.themeColor = col;
    }
    selectColor = col;
    selectModel = mode;
    notifyListeners();
  }
//初始化加载
  onLoad(context) {
    this.context = context;
    provider = Provider.of(context);
    selectModel = provider.getThemeMode();
    selectColor = provider.getThemColor();
    setIdly();
  }
}

详细使用详见源码

四. 使用到的颜色工具类

import 'dart:ui';

import 'package:flutter/material.dart';

class ColorUtil{
  ///判断一个颜色是否是亮色 用来判断反色
  static bool isLightColor(Color color){
    double darkness =  1 - (0.299 * color.red + 0.587 * color.green + 0.114 * color.blue) / 255;
    return darkness<0.5;
  }
  //判断它是不是白色
  static bool isWhiteColor(Color color){
    return color.value.toRadixString(16) == "ffffffff";
  }
  /// Construct a color from a hex code string, of the format #RRGGBB.
  static Color hexToColor(String? code) {
    if (code==null||code==""|| code.length != 7) {
      return Colors.blue;
    }
    return Color(int.parse(code.substring(1, 7), radix: 16) + 0xFF000000);
  }

  ///创建Material风格的color
  static MaterialColor createMaterialColor(Color color) {
    List strengths = [.05];
    Map swatch = {};
    final int r = color.red, g = color.green, b = color.blue;

    for (int i = 1; i < 10; i++) {
      strengths.add(0.1 * i);
    }
    for (var strength in strengths) {
      final double ds = 0.5 - strength;
      swatch[(strength * 1000).round()] = Color.fromRGBO(
        r + ((ds < 0 ? r : (255 - r)) * ds).round(),
        g + ((ds < 0 ? g : (255 - g)) * ds).round(),
        b + ((ds < 0 ? b : (255 - b)) * ds).round(),
        1,
      );
    }
    return MaterialColor(color.value, swatch as Map);
  }

  /// 颜色检测只保存 #RRGGBB格式 FF透明度
  /// [color] 格式可能是材料风/十六进制/string字符串
  /// 返回[String] #rrggbb 字符串
  static String? color2HEX(Object? color) {
    if (color is Color) {
      // OxFFFFFFFF
      //将十进制转换成为16进制 返回字符串但是没有0x开头
      String temp = color.value.toRadixString(16);
      color = "#" + temp.substring(2, 8);
    }
    return color.toString();
  }
}

源码地址:链接:https://pan.baidu.com/s/1iip8W3jy0YmWqMIaLhih5Q
提取码:xisr

版权声明:
作者:Zad
链接:https://www.techfm.club/p/47688.html
来源:TechFM
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>