基于ThemeData 实现主题切换
1. 实现可以亮暗主题切换
2. 实现可以颜色主题的切换
3.当主题为白色的时候替换一个其他主颜色
4.当颜色为浅色时候需要做反色处理
演示效果
一. 修改Main.dark 文件
//多Provider 当前只用了一个 为以后打基础
return MultiProvider(
providers: [
ChangeNotifierProvider<ThemeViewModel>(
create: (context) => ThemeViewModel(),
),
],
child: Consumer<ThemeViewModel>(
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 => <String>['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<String>(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<String>(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<String>(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<Map<String, dynamic>> modelItem = [
{"name": '跟随系统', "mode": ThemeMode.system},
{"name": '白天模式', "mode": ThemeMode.light},
{"name": '夜间模式', "mode": ThemeMode.dark},
];
//创建主题颜色
List<String> 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<ThemeViewModel>(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 = <double>[.05];
Map swatch = <int, Color>{};
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<int, Color>);
}
/// 颜色检测只保存 #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