Flutter狀態管理終極方案GetX第一篇——路由

我用 GetX寫了一個使用demo,和一個app,demo中導航的演示如下:



代碼示例

前言

GetX 是 Flutter 上的一個輕量且強大的解決方案:高性能的狀態管理、智能的依賴注入和便捷的路由管理。

爲什麼是 GetX,而不是 BLoC、MobX、Provider?

BLoC 非常安全和高效,但是對於初學者來說非常複雜,即使學會,樣板代碼也很多。

MobX 比 BLoC 更容易,而且是響應式的,但是需要使用一個代碼生成器,需要等很久,這降低了生產力。

GetX我喜歡的地方:

  • 輕量。模塊單獨編譯,沒用到的功能不會編譯進我們的代碼。
  • 語法簡潔。個人非常喜歡,顯而易見且實用,比如路由擺脫了 context 的依賴,Get.to(SomePage())就能導航到新路由。
  • 性能。Provider、BLoC 等只能在父子組件保存狀態,同層級模塊狀態管理需要全局處理,存活在整個應用生命週期。而 GetX 可以隨時添加控制器和刪除控制器,並且會自動釋放使用完的控制器。
  • 依賴注入。提供依賴注入功能,代碼層級可以完全分離,甚至依賴注入的代碼也是分離的。
  • 豐富的api。許多複雜的操作,使用 GetX 就會有簡單的實現。

有的同學看過我寫的Flutter狀態管理provider的使用和封裝,講解了 Provider 的使用,其實在使用過程中發現了許多痛點,最致命的是 Provider 使用InheritedWidget 來傳遞相同的監聽器,這意味着對其 ChangeNotifier 類的任何訪問都必須在父子widget樹內。非父子組件的狀態管理問題,需要藉助別的手段(eventbus,全局,單例),十分痛苦,在改用GetX後,越來越舒服了。


路由

普通路由導航

打開到新的頁面:

Get.to(NextScreen());

對應原生路由:

    Navigator.push(context, MaterialPageRoute<void>(
      builder: (BuildContext context) {
        return NextScreen();
      },
    ));

返回:

Get.back();

對應原生路由:

    Navigator.pop(context);

打開新頁面,並且用新頁面替換舊頁面(刪除舊頁面):

Get.off(NextScreen());

對應原生路由:

 Navigator.pushReplacement(context, MaterialPageRoute<void>(
      builder: (BuildContext context) {
        return NextScreen();
      },
    ));

打開新頁面並刪除之前的所有路由:

Get.offAll(NextScreen());

對應原生路由:

   Navigator.pushAndRemoveUntil(
      context,
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          return NextScreen();
        },
      ),
      (Route<dynamic> route) => false,
    );

導航到新頁面,在返回時接收返回數據:

var data = await Get.to(NextScreen());

對應原生路由:

    var data = await  Navigator.push(context, MaterialPageRoute<void>(
      builder: (BuildContext context) {
        return NextScreen();
      },
    ));

帶返回值返回前一個路由,配合上面使用:

Get.back(result: 'success');

對應原生路由:

 Navigator.pop(context, 'success');

別名路由導航

  1. 聲明別名:
abstract class Routes {
  static const Initial = '/';
  static const NextScreen = '/NextScreen';

}
  1. 註冊路由表:
abstract class AppPages {
  static final pages = [
    GetPage(
      name: Routes.Initial,
      page: () => HomePage(),
    ),
    GetPage(
      name: Routes.NextScreen,
      page: () => NextScreen(),
    ),
  ];
}

  1. 替換MaterialApp爲GetMaterialApp:
void main() {
  runApp(GetMaterialApp(
    debugShowCheckedModeBanner: false,
    initialRoute: '/',
    theme: appThemeData,
    defaultTransition: Transition.fade,
    getPages: AppPages.pages,
    home: HomePage(),
  ));
}

使用

導航到下一個頁面:

Get.toNamed(Routes.NextScreen);

導航到下一個頁面並刪除前一個頁面:

Get.offNamed(Routes.NextScreen);

導航到下一個頁面並刪除以前所有的頁面:

Get.offAllNamed(Routes.NextScreen);

發送數據到別名路由:

Get在這裏接受任何東西,無論是一個字符串,一個Map,一個List,甚至一個類的實例。

Get.toNamed(Routes.NextScreen, arguments: '新垣結衣');

獲取參數:

String name=Get.arguments;

動態網頁鏈接:

像web一樣攜帶參數,適合前端開發的風格。

Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");

獲取參數:

int id = Get.parameters['id'];
// out: 354
String name=Get.parameters['name'];

還可以這樣定義路由別名:

       GetPage(
        name: '/profile/:user',
        page: () => UserProfile(),
      ),

導航:

Get.toNamed("/profile/34954");

在第二個頁面上,通過參數獲取數據

print(Get.parameters['user']);
// out: 34954

中間件

在跳轉前做些事情,比如判斷是否登錄,可以使用routingCallback來實現:

GetMaterialApp(
  routingCallback: (routing) {
    if(routing.current == '/second'){
     // 如果登錄。。。
    }
  }
)

小部件導航

SnackBars

彈出:

Get.snackbar('Hi', 'i am a modern snackbar');

對應原生寫法:

final snackBar = SnackBar(
  content: Text('Hi!'),
  action: SnackBarAction(
    label: 'I am a old and ugly snackbar',
    onPressed: (){}
  ),
);

//用Flutter創建一個簡單的SnackBar,你必須獲得Scaffold的context,或者你必須使用一個GlobalKey附加到你的Scaffold上。

Scaffold.of(context).showSnackBar(snackBar);

Dialogs

打開一個默認的Dialog:

Get.defaultDialog(
  onConfirm: () => print("Ok"),
  middleText: "Dialog made in 3 lines of code"
);

打開自定義的Dialog:

Get.dialog(YourDialogWidget());

BottomSheets

Get.bottomSheet類似於showModalBottomSheet,但不需要context:

Get.bottomSheet(
  Container(
    child: Wrap(
      children: <Widget>[
        ListTile(
          leading: Icon(Icons.music_note),
          title: Text('Music'),
          onTap: () => {}
        ),
        ListTile(
          leading: Icon(Icons.videocam),
          title: Text('Video'),
          onTap: () => {},
        ),
      ],
    ),
  )
);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章