Flutter狀態(tài)管理之 Getx

在Flutter開發(fā)中狀態(tài)管理是必不可少的,這個和前端vue的開發(fā)類似。flutter原生提供狀態(tài)管理組件InheritedWidget功能單一,使用場景有限,不過flutter社區(qū)有很多優(yōu)秀的狀態(tài)管理插件:如筆者一直用的是 provider,它可以實(shí)現(xiàn)主題切換、灰色模式、暗黑模式等常見的App的功能。和provider不同的是 Getx更加的強(qiáng)大。我們可以認(rèn)為Getx是flutter的一個框架,它不僅提供了狀態(tài)管理,還提供了一些常用的組件、路由管理等。

在使用Getx之前,我們不能著急上馬,應(yīng)認(rèn)真讀一下官方說明,具體詳見https://pub.dev/packages/get,在官方的前言里面有矚目的Getx說明,需要重點(diǎn)關(guān)注:

1 性能:Getx專注于性能和資源消耗最小。Getx不使用Streams或ChangeNotifier。
2 Getx允許視圖、演示邏輯、業(yè)務(wù)邏輯、依賴注入和導(dǎo)航的完全解耦。您不需要上下文來在路由之間導(dǎo)航,因此您不依賴小部件樹(可視化)。您不需要上下文來通過 inheritedWidget訪問控制器/塊,因此您可以將演示邏輯和業(yè)務(wù)邏輯與可視化層完全解耦。您不需要通過MultiProvider將Controllers/Models/Blocs類注入到小部件樹中。為此,GetX使用自己的依賴注入功能,將DI與其視圖完全解耦。
3 如果您僅將Getx用于狀態(tài)管理或依賴項(xiàng)管理,則無需使用GetMaterialApp。GetMaterialApp對于與路由和無上下文相關(guān)的路由、小組件、國際化、sheet、對話框和高級apis是必要的。

Getx簡單使用

導(dǎo)入頭文件import 'package:get/get.dart';

1 在mian.dart里面使用GetMaterialApp,其實(shí)這樣使用Getx對工程的侵入非常大的,所以在項(xiàng)目的初期應(yīng)該考慮是否使用Getx,而不是隨著項(xiàng)目深入使用GetMaterialApp。
2 常用的小組件
2.1 snackbar

Get.snackbar("Snackbar 標(biāo)題", "歡迎使用Snackbar");

2.2 Dialog

Get.defaultDialog();

2.3 Sheet

Get.bottomSheet()

3 路由router

Getx的路由是調(diào)研過程中最大的收獲,無論使用flutter自帶的路由,還是使用第三方路由,都離不開 context,有些路由需要使用命令才能生成路由,比如auto_route,需要在dev_dependencies;生成路由:aauto_route_generatorflutter packages pub run build_runner build,使用起來比較啰嗦。那么Getx的路由完全和context隔離,只需要Get.to(OhterPageWidget()),就可以跳轉(zhuǎn)界面。to()方法接口也非常豐富,也可以自定義動畫,轉(zhuǎn)場動畫等。

Future<T?>? to<T>(
    dynamic page, {
    bool? opaque,
    Transition? transition,
    Curve? curve,
    Duration? duration,
    int? id,
    String? routeName,
    bool fullscreenDialog = false,
    dynamic arguments,
    Bindings? binding,
    bool preventDuplicates = true,
    bool? popGesture,
    double Function(BuildContext context)? gestureWidth,
  }) 

除了to()方法外,還可用用toNamed;
在main.dart入口設(shè)置路由路徑:

 getPages: [
// 首頁
         GetPage(name: "/home", page: ()=>Home()),
// 我的
         GetPage(name: "/mine", page: ()=>Minne()),
// 設(shè)置
         GetPage(name: "/setting", page: ()=>Setting())
      ],

使用toNamed方法 Get.toNamed("/home")。

4 狀態(tài)管理

在學(xué)習(xí)狀態(tài)管理之前我們需要了解ObxGetxController。
Obx關(guān)于它官方是這樣描述的:

  反應(yīng)狀態(tài)管理器(GetX/Obx):
 反應(yīng)式編程可以疏遠(yuǎn)許多人,因?yàn)樗鼡?jù)說很復(fù)雜。GetX將反應(yīng)式編程變成了非常簡單的事情:

您不需要創(chuàng)建StreamController。
您不需要為每個變量創(chuàng)建StreamBuilder
您無需為每個州創(chuàng)建類。
您無需為初始值創(chuàng)建get。
你不需要使用代碼生成器
使用Get進(jìn)行反應(yīng)式編程就像使用setState一樣簡單。

比如我們觀察var name = 'Jonatas Borges'的變化,只需寫成var name = 'Jonatas Borges'.obs,除了給屬性值后面添加.obs外,還有2種定義Obx變量的方法:
第一種 使用 Rx{Type} 。
final name = RxString('Jonatas Borges');
第二種是使用 Rx,規(guī)定泛型 Rx<Type>
final name = Rx<String>('Jonatas Borges');

GetxController主要的作用是用于UI代碼與業(yè)務(wù)邏輯分離開來。下面是個簡單的使用:

class Controller extends GetxController {
   var count = 0.obs;
  var age = 18.obs;
  void increment() => count++;
 @override
  void onInit() {
    super.onInit();
    //監(jiān)聽count的值變化
    ever(count, (callback) => print("count"));
    // 監(jiān)聽count age的值
    everAll([count, age], (callback) => print(callback));
    once(count, (callback) => print("count值改變時(shí)調(diào)用,只執(zhí)行一次"));
    debounce(count, (callback) => print("1s后調(diào)用,防止DDos"));
    interval(count, (callback) => print("忽略1s內(nèi)所有變動"));
  }
}
...
 appBar: AppBar(
        title: Obx(
// 展示count
          () => Text("Clicks: ${c.count}"),
        ),
      ),

...
floatingActionButton: FloatingActionButton(
// 修改count
        onPressed: () => c.increment(),
        child: Icon(Icons.add),
      ),

uniqueIDGetxController監(jiān)聽過程中,單獨(dú)在某個GetBuilder上設(shè)置。這樣更好的管理這個狀態(tài)。

```tag```:區(qū)分不同的控制器來實(shí)現(xiàn)不同的功能,減少控制器代碼量和重復(fù)創(chuàng)建。
 class Controller extends GetxController {
  ...
    void testUniqueID() {
    age += 10;
    //  home_age_id:uniqueID
    update(["home_age_id"]);
  }
  ...
}
 
 final Controller c = Get.put(Controller());
    // print(c);
    return Scaffold(
      body: Column(
        children: [
        //GetBuilder   <Controller> 必須指定 不然會崩潰?。?!
          GetBuilder<Controller>(
            id: "home_age_id",
           tag:"tagxxxx",
            builder: (controller) {
              return Obx(
                () => Text("Clicks: ${c.age}"),
              );
              //  return Text("1111");
              // return Text("年齡值為: ${c.age}",);
            },
          ),
          ElevatedButton(
            onPressed: () => c.testUniqueID(),
            child: Text("增加年齡"),
          )
        ],
      ),
    );

4 國際化配置

國際化配置是狀態(tài)管理領(lǐng)域的一個重要應(yīng)用,使用 Getx非常快捷方便,是做這種應(yīng)用的不二選擇。

1 自定義個繼承與Translations的類,重寫keys
class InternationalConfigure extends Translations {
 @override
 // TODO: implement keys
 Map<String, Map<String, String>> get keys => {
       'zh_CN': {
        'hello': "你好, GetX"
       },
       'en_US': {
         'hello': 'Hello GetX',
       },
     };
}
2 在入口出國際化配置
 GetMaterialApp {
   
 ...
  translations: InternationalConfigure(),
     // 設(shè)置默認(rèn)語言
     locale: Locale("zh",'CN'),
     // 在配置錯誤的情況下 顯示的語言
     fallbackLocale: Locale("zh",'CN'),
 ...

}
3 使用國際化配置

首先在狀態(tài)管理類里實(shí)現(xiàn)updateLocale 方法,

class Controller extends GetxController {
     ...
    void changeLanguage(String languageCode, String countryCode) {
    Get.updateLocale(Locale(languageCode, countryCode));
  }
 ...
}

然后就可以切換使用了。

     Text('hello'.tr, style: TextStyle(color: Colors.pink, fontSize: 30)),
  ElevatedButton(
        onPressed: () => c.changeLanguage('zh', 'CN'),
        child: Text("切換中文"),
      ),

      ElevatedButton(
        onPressed: () => c.changeLanguage('en', 'US'),
        child: Text("切換英文"),
      ),
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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