序:原生的主題切換只能切換屬性對應(yīng)的固定部件,自己繼承創(chuàng)建的文字顏色或者背景色無法跟隨主題切換而切換
這篇將會解決手動切換主題以及跟隨手機(jī)切換主題來更新UI(包括自己創(chuàng)建的Widget)
一、原生主題支持的屬性切換主題
factory ThemeData({
Brightness brightness, // 應(yīng)用主題亮度,可選(dark、light)
VisualDensity visualDensity, // 視覺密度
MaterialColor primarySwatch, // 主要樣式,設(shè)置primaryColor后該背景色會被覆蓋
Color primaryColor, // 主要部分背景顏色(導(dǎo)航和tabBar等)
Brightness primaryColorBrightness, // primaryColor的亮度
Color primaryColorLight, // primaryColor的淺色版
Color primaryColorDark, // primaryColor的深色版
Color accentColor, // 前景色(文本,按鈕等)
Brightness accentColorBrightness, // accentColor的亮度
Color canvasColor, // MaterialType.canvas 的默認(rèn)顏色
Color shadowColor, // 陰影顏色
Color scaffoldBackgroundColor, // Scaffold的背景顏色。典型Material應(yīng)用程序或應(yīng)用程序內(nèi)頁面的背景顏色
Color bottomAppBarColor, // BottomAppBar的默認(rèn)顏色
Color cardColor, // Card的顏色
Color dividerColor, // Divider和PopupMenuDivider的顏色,也用于ListTile之間、DataTable的行之間等。
Color focusColor, // 突出顏色
Color hoverColor, // hoverColor
Color highlightColor, // 高亮顏色,選中在潑墨動畫期間使用的突出顯示顏色,或用于指示菜單中的項(xiàng)。
Color splashColor, // 墨水飛濺的顏色。InkWell
InteractiveInkFeatureFactory splashFactory, // 定義由InkWell和InkResponse反應(yīng)產(chǎn)生的墨濺的外觀。
Color selectedRowColor, // 用于突出顯示選定行的顏色。
Color unselectedWidgetColor, // 用于處于非活動(但已啟用)狀態(tài)的小部件的顏色。例如,未選中的復(fù)選框。通常與accentColor形成對比。也看到disabledColor。
Color disabledColor, // 禁用狀態(tài)下部件的顏色,無論其當(dāng)前狀態(tài)如何。例如,一個禁用的復(fù)選框(可以選中或未選中)。
Color buttonColor, // RaisedButton按鈕中使用的Material 的默認(rèn)填充顏色。
ButtonThemeData buttonTheme, // 定義按鈕部件的默認(rèn)配置,
ToggleButtonsThemeData toggleButtonsTheme, // 切換按鈕的主題
Color secondaryHeaderColor, // 選定行時PaginatedDataTable標(biāo)題的顏色。
Color textSelectionColor, // 文本框中文本選擇的顏色,如TextField
Color cursorColor, // 文本框中光標(biāo)的顏色,如TextField
Color textSelectionHandleColor, // 調(diào)整當(dāng)前選定的文本部分的句柄的顏色。
Color backgroundColor, // 與主色形成對比的顏色,例如用作進(jìn)度條的剩余部分。
Color dialogBackgroundColor, // Dialog元素的背景顏色
Color indicatorColor, // 選項(xiàng)卡中選定的選項(xiàng)卡指示器的顏色。
Color hintColor, // 用于提示文本或占位符文本的顏色,例如在TextField中。
Color errorColor, // 用于輸入驗(yàn)證錯誤的顏色,例如在TextField中
Color toggleableActiveColor, // 用于突出顯示Switch、Radio和Checkbox等可切換小部件的活動狀態(tài)的顏色。
String fontFamily, // 文本字體
TextTheme textTheme, // 文本的顏色與卡片和畫布的顏色形成對比。
TextTheme primaryTextTheme, // 與primaryColor形成對比的文本主題
TextTheme accentTextTheme, // 與accentColor形成對比的文本主題。
InputDecorationTheme inputDecorationTheme, // 基于這個主題的 InputDecorator、TextField和TextFormField的默認(rèn)InputDecoration值。
TabBarTheme tabBarTheme, // 用于自定義選項(xiàng)卡欄指示器的大小、形狀和顏色的主題。
TooltipThemeData tooltipTheme, // tooltip主題
CardTheme cardTheme, // Card的顏色和樣式
AppBarTheme appBarTheme, // appBar主題
ColorScheme colorScheme, // 擁有13種顏色,可用于配置大多數(shù)組件的顏色。
NavigationRailThemeData navigationRailTheme, // 導(dǎo)航邊欄主題
// ...
})
代碼
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// //國際化
// return GetMaterialApp(
// .......
// .......
//設(shè)置默認(rèn)主題 深色主題 通過 Get.changeThemeMode 直接來切換
// theme: appLightThemeData,
// darkTheme: appDarkThemeData,
//themeMode: ThemeMode.light,
//創(chuàng)建Dark ThemeData對象
final ThemeData appDarkThemeData = ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.red, // 主要部分背景顏色(導(dǎo)航和tabBar等)
scaffoldBackgroundColor:
Colors.red, //Scaffold的背景顏色。典型Material應(yīng)用程序或應(yīng)用程序內(nèi)頁面的背景顏色
textTheme: TextTheme(headline1: TextStyle(color: Colors.yellow, fontSize: 15)),
appBarTheme: AppBarTheme(iconTheme: IconThemeData(color: Colors.yellow)));
//創(chuàng)建light ThemeData對象
final ThemeData appLightThemeData = ThemeData(
brightness: Brightness.light,
primaryColor: Colors.white, // 主要部分背景顏色(導(dǎo)航和tabBar等)
scaffoldBackgroundColor:
Colors.white, //Scaffold的背景顏色。典型Material應(yīng)用程序或應(yīng)用程序內(nèi)頁面的背景顏色
textTheme: TextTheme(headline1: TextStyle(color: Colors.blue, fontSize: 15)),
appBarTheme: AppBarTheme(iconTheme: IconThemeData(color: Colors.black)));
class GetXThemes extends StatelessWidget {
const GetXThemes({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("主題"),
),
body: Center(
child: TextButton(
onPressed: () {
//直接設(shè)置Theme
Get.changeTheme(
Get.isDarkMode ? appLightThemeData : appDarkThemeData);
//設(shè)置ThemeMode
// Get.changeThemeMode(ThemeMode.dark);
},
child: Text(
"更換主題",
style: Get.textTheme.headline1,//這里有個問題,就是主題切換,這里的Text并不會更新
),
),
),
);
}
}
二、自創(chuàng)建Widget的顏色隨主題變化方案
主題切換有個問題,就是如果是我們自定義或者在build()自己創(chuàng)建的部件是不會隨著系統(tǒng)的主題切換而發(fā)生主題色變化的(實(shí)際測試中,如果頁面在頂層(沒有被push)切換主題并不會觸發(fā)build()方法,(push之后的頁面切換系統(tǒng)主題是可以觸發(fā)build()的,而且會頻繁觸發(fā)好多次...),既然無法通過重新build更新組件的主題色,那么我們在切換主題后,強(qiáng)制觸發(fā)整個app的build()就可以了)
- 1.
Get.forceAppUpdate();強(qiáng)制觸發(fā)build()
這個方法是從Getx國際化更換語言里找到的Get.updateLocale(Locale("en"));
//手動切換主題
Get.changeThemeMode( Get.isDarkMode ? ThemeMode.light : ThemeMode.dark);
//這里要設(shè)置個延遲,在調(diào)用切換主題后并不能立刻生效,會有點(diǎn)延遲,
// 如果不設(shè)置延遲會導(dǎo)致取的還是上個主題狀態(tài)
Future.delayed(Duration(milliseconds: 250), () {
//強(qiáng)制觸發(fā) build
Get.forceAppUpdate();
if (Get.isDarkMode) {
print("轉(zhuǎn)換后 darkMode");
} else {
print("轉(zhuǎn)換后 lightMode");
}
});
- 2.小尾巴-到了這里看似已經(jīng)沒問題了,但是還有一個忽略的地方,就是在設(shè)置主題時,還有一個選項(xiàng)就是跟隨系統(tǒng)
themeMode: ThemeMode.system,,就是用戶在手機(jī)上設(shè)置了主題,app的主題跟隨手機(jī)設(shè)置走,那我們自定義的組件就又不能夠跟隨切換主題色了.解決辦法就是監(jiān)聽手機(jī)的主題切換,如下創(chuàng)建一個單例,這個單例只要在WidgetsFlutterBinding.ensureInitialized();后初始化即可,否則WidgetsBinding.instance可能為null
void main() {
//確保 WidgetsBinding.instance 后續(xù)使用沒有問題
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class AppLifeCycleDelegate with WidgetsBindingObserver {
static final AppLifeCycleDelegate _appLifeCycleDelegate =
AppLifeCycleDelegate._inital();
AppLifeCycleDelegate._inital() {
print("初始化生命周期代理");
WidgetsBinding.instance?.addObserver(this);
}
factory AppLifeCycleDelegate() {
return _appLifeCycleDelegate;
}
@override
void didChangePlatformBrightness() {
// TODO: implement didChangePlatformBrightness
super.didChangePlatformBrightness();
print("手機(jī)主題發(fā)生變化");
//強(qiáng)制觸發(fā) build
Get.forceAppUpdate();
}
}