flutter 完全使用GetX 主題切換 以及 自創(chuàng)建Widget的顏色隨主題變化方案

序:原生的主題切換只能切換屬性對應(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();
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容