App項(xiàng)目一鍵換膚功能比較常見(jiàn)了,一般項(xiàng)目都附帶有該功能互婿,由于近期項(xiàng)目?jī)?nèi)也加入了此功能捣郊,也順帶記錄下過(guò)程。
由于產(chǎn)品說(shuō)還想要從后臺(tái)配置相關(guān)配色慈参,通過(guò)后臺(tái)隨時(shí)控制呛牲,所以我反手就給他一個(gè)大比兜,然后就開寫代碼了~ (づ ̄3 ̄)づ╭?~
首先第一步先配置下主題相關(guān):
創(chuàng)了一個(gè)類專門管理以及處理顏色讀取相關(guān):
abstract class ThemeColorConfig {
//正常模式驮配、也可讀取后臺(tái)數(shù)據(jù)模式
Map<String, dynamic> normalColorInfo = {};
//暗黑模式娘扩、可跟隨系統(tǒng)
Map<String, dynamic> darkColorInfo = {};
Color configColor(String colorKey) {
//讀取是否是暗黑模式 這里是讀取存儲(chǔ)的模式,使用的SpUtil封裝的壮锻,比較簡(jiǎn)易琐旁,就不貼了
String isDark = CommonSpUtil.getThemeType();
Map colorInfo = isDark == "isDark" ? darkColorInfo : normalColorInfo;
return ColorsUtil.hexToColor(colorInfo[colorKey]);
}
}
class ThemColorUtil extends ThemeColorConfig {
@override
// TODO: implement darkColorInfo
// 暗黑模式,可隨系統(tǒng)變化
Map<String, dynamic> get darkColorInfo => {
'backgroundColor': "#2865ff",
'text': "#6A5ACD",
'button': "#1E90FF",
'content': "#000000",
'themColor': "#8A2BE2",
'line': "#999999",
'space': "#E8E8E8",
'cloc3c3c3': "#c3c3c3",
'redText': "#FF6650",
'cloC6C9DB': "#C6C9DB",
};
@override
// TODO: implement normalColorInfo
// 正常模式猜绣、也可讀取后臺(tái)數(shù)據(jù)模式
Map<String, dynamic> get normalColorInfo =>
SpUtil.getString("colorMaps")!.isNotEmpty
? jsonDecode(SpUtil.getString("colorMaps")!)
: {
'text': "#66FFCC",
'button': "#1F1D2B",
'backgroundColor': "#1F1D2B",
'content': "#000000",
'themColor': "#1F1D2B",
'line': "#999999",
'space': "#E8E8E8",
'c3c3c3': "#c3c3c3",
'redText': "#FF6650"
};
}
創(chuàng)建一個(gè)ColorsUtil類灰殴,以及使用上面類來(lái)管理顏色以及主要主題色,便于使用和取值:
class ColorsUtil {
// 顏色鍵值掰邢,取值用
static String them = "themColor";
static String background = "backgroundColor";
static String text = "text";
static String button = "button";
static String content = "content";
static String line = "line";
static String space = "space";
static String cloc3c3c3 = "cloc3c3c3";
static String redText = "redText";
static String cloC6C9DB = "cloC6C9DB";
/// 十六進(jìn)制顏色牺陶,
/// hex, 十六進(jìn)制值,例如:0xffffff,
/// alpha, 透明度 [0.0,1.0]
static Color hexToColor(dynamic string) {
/// 如果傳入的十六進(jìn)制顏色值不符合要求辣之,返回默認(rèn)值
if (string == null ||
string.length != 7 ||
int.tryParse(string.substring(1, 7), radix: 16) == null) {
string = '#999999';
}
return Color(int.parse(string.substring(1, 7), radix: 16) + 0xFF000000);
}
///生成隨機(jī)顏色
static Color randomColor() {
return Color.fromRGBO(
Random().nextInt(255), Random().nextInt(255), Random().nextInt(255), 1);
}
/// 項(xiàng)目主題色
Color themeColor = ThemColorUtil().configColor(
them); //Color(0xFF1F1D2B); //ColorsUtil.hexToColor("#1F1D2B");
/// 項(xiàng)目背景色
Color backgroundColor = ThemColorUtil().configColor(background);
/// 文本
Color textColor = ThemColorUtil().configColor(text);
/// cloC6C9DB
Color colorC6C9DB = ThemColorUtil().configColor(cloC6C9DB);
}
好了掰伸,主題色值基本配置完畢,可以本地設(shè)置好多種膚色或者通過(guò)后臺(tái)接口請(qǐng)求來(lái)怀估,然后根據(jù)鍵值對(duì)進(jìn)行對(duì)比取值即可狮鸭。
第二步:
切換主題:
class ThemeTool {
/// 切換主題
static changeTheme() {
ThemeMode mode = getLocalThemeModel();
ThemeData themeData = getLocalThemeData();
EasyLoadingStyle easyLoadingStyle = EasyLoadingStyle.dark;
if (mode == ThemeMode.dark) {
easyLoadingStyle = EasyLoadingStyle.light;
} else if (mode == ThemeMode.system) {
if (!Get.isDarkMode) {
easyLoadingStyle = EasyLoadingStyle.light;
}
}
EasyLoading.instance.loadingStyle = easyLoadingStyle;
Get.changeThemeMode(mode);
Get.changeTheme(themeData);
//這里設(shè)置這個(gè)延遲原因是:在調(diào)用切換主題后,無(wú)法立即生效奏夫,會(huì)有一些延遲怕篷,如果不延遲會(huì)讀取還是上個(gè)主題
//使用Get 強(qiáng)制更新app狀態(tài)
Future.delayed(const Duration(milliseconds: 300), () {
print("執(zhí)行這里");
Get.forceAppUpdate();
});
}
/// 獲取本地 主題配置
static getLocalThemeModel() {
//讀取是否是暗黑模式
String isDark = CommonSpUtil.getThemeType();
ThemeMode themeMode = ThemeMode.light;
if (isDark == "isDark") {
themeMode = ThemeMode.system;
} else {
themeMode = ThemeMode.light;
}
return themeMode;
}
static getLocalThemeData() {
//讀取是否是暗黑模式
String isDark = CommonSpUtil.getThemeType();
ThemeData themeData = ThemeData.light();
if (isDark == "isDark") {
if (!Get.isDarkMode) {
themeData = ThemeData(brightness: Brightness.dark);
} else {
themeData = ThemeData(brightness: Brightness.light);
}
} else {
themeData = ThemeData(brightness: Brightness.light);
}
return themeData;
}
}
最后,配置main入口函數(shù)中的GetMaterialApp:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(375, 812),
builder: (context, w) {
return GetMaterialApp(
title: 'App',
debugShowCheckedModeBanner: false,
initialBinding: InitBinding(),
initialRoute: RouterUtil.tabBar,
getPages: RouterUtil.getPages,
// translations: StringRes(),
defaultTransition: Transition.cupertino,
locale: LocaleTool.languageConfig().isNotEmpty
? Locale(LocaleTool.languageConfig()[0],
LocaleTool.languageConfig()[1])
: null, //默認(rèn)展示本地語(yǔ)言
fallbackLocale: const Locale('zh', 'CN'), //語(yǔ)言選擇無(wú)效時(shí)酗昼,備用語(yǔ)言
/// 支持語(yǔ)言
supportedLocales: S.delegate.supportedLocales,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
CustomLocalDelegate.delegate,
S.delegate
],
theme: ThemeData(brightness: Brightness.light),
darkTheme: ThemeData(brightness: Brightness.dark),
**/// 配置 本地存儲(chǔ) 主題類型**
themeMode: ThemeTool.getLocalThemeModel(),
builder: EasyLoading.init(builder: (context, child) {
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus &&
currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
},
child: child,
);
}),
);
},
);
}
}
到這一步基本一鍵切換主題廊谓,就基本完成了,可以盡情切換了麻削。(當(dāng)時(shí)我也以為完事了蒸痹,但是忽略了一個(gè)問(wèn)題春弥,跟隨系統(tǒng)可變)
上面配置完以后,通過(guò)測(cè)試發(fā)現(xiàn)叠荠,無(wú)法跟隨系統(tǒng)變那匿沛,不符合需求,那么就需要監(jiān)聽手機(jī)的主題切換了榛鼎。
我們可以在項(xiàng)目首頁(yè)home_page內(nèi)逃呼,繼承WidgetsBindingObserver來(lái)監(jiān)聽
@override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addObserver(this);
}
重寫:didChangePlatformBrightness方法,在此方法內(nèi)切換主題即可
@override
void didChangePlatformBrightness() {
// 系統(tǒng)自動(dòng)變化者娱、切換暗黑模式和正常模式抡笼,回調(diào)方法
// TODO: implement didChangePlatformBrightness
super.didChangePlatformBrightness();
ThemeTool.changeTheme(); //監(jiān)測(cè) 自動(dòng)切換暗黑和正常模式
}
效果如下:
我這目前只演示了替換導(dǎo)航顏色,其他文本以及顏色目前未全部處理黄鳍,不過(guò)千篇一律推姻,按照色值讀取以及設(shè)置即可~
長(zhǎng)風(fēng)破浪會(huì)有時(shí),直掛云帆濟(jì)滄海框沟!加油~