Flutter GetX使用---簡潔的魅力!

前言

使用Bloc的時候,有一個讓我至今爲止十分在乎的問題,沒法真正的跨頁面交互!在反覆的查閱官方文檔後,使用一個全局Bloc的方式,實現了「僞」跨頁面交互,詳細可查看: flutter_bloc使用解析;fish_redux的廣播機制是能夠比較完美的實現跨頁面交互的,我也寫了一篇近萬字介紹如何使用該框架: fish_redux使用詳解,對於中小型項目使用fish_redux,這會必定程度上下降開發效率,最近嘗試了GetX相關功能,解決了個人至關一部分痛點

把整篇文章寫完後,我立刻把本身的一個demo裏面全部Bloc代碼全用GetX替換,且去掉了Fluro框架;感受用Getx雖然會省掉大量的模板代碼,但仍是有些重複工做:建立文件夾,建立幾個必備文件,寫那些必需要寫的初始化代碼和類;略微繁瑣,爲了對得起GetX給我開發帶來的巨大便利,我就花了一些時間,給它寫了一個插件! 上面這重複的代碼,文件,文件夾通通能一鍵生成!html

GetX相關優點java

  • build刷新方法極度簡單!git

    • getx:Obx(() => Text())
    • 這是我很是很是在乎的一個方面,由於bloc的build刷新組件方法要傳倆個泛型,加上build方法裏面的倆個參數,致使一個build方法若是不使用箭頭方法簡寫,幾乎佔四五行,用起來實在蛋筒,致使我平時開發直接把BlocBuilder方法直接寫在頁面頂層(不提倡寫頂層),一個頁面只用寫一次了,不用定點處處寫BlocBuilder了,手動滑稽.jpg
  • 跨頁面交互github

    • 這絕對是GetX的一個優勢!對於複雜的生產環境,跨頁面交互的場景,實在太常見了,GetX的跨頁面交互,幾乎和fish_redux同樣簡單,愛了愛了
  • 路由管理web

    • 是的,getx內部實現了路由管理,並且用起來,那叫一個簡單!bloc沒實現路由管理,這讓我不得不去找一個star量高的路由管理框架,就選擇了fluro,可是讓我不得不說,這個fluro用起來真的叫一個折磨人,每次新建一個頁面,最讓我抗拒的就是去寫fluro路由代碼,橫跨幾個文件來回寫,真是肝疼
    • GetX實現了動態路由傳參,也就是說直接在命名路由上拼參數,而後能拿到這些拼在路由上的參數,也就是說用flutter寫H5,直接能經過Url傳值(fluro也能作到),OMG!能夠無腦捨棄複雜的fluro了
  • 實現了全局BuildContext
  • 國際化,主題實現

上面單單是build簡寫的優點,就會讓我考慮是否去使用了,並且還能實現跨頁面的功能,這還考慮啥,開搞!redux

下來將全面的介紹GetX的使用,文章也不分篇水閱讀量了,力求一文寫清楚,方便你們隨時查閱api

準備

引入

  • 首先導入GetX的插件
# getx 狀態管理框架 https://pub.flutter-io.cn/packages/get
get: ^3.24.0

GetX地址app

主入口配置

  • 只須要將MaterialApp改爲GetMaterialApp便可
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: CounterGetPage(),
    );
  }
}
  • 各模塊導包,均使用下面包便可
import 'package:get/get.dart';

插件

吐槽下寫插件的過程,實際寫這種模板代碼生成插件,其實也不難,網上有不少人寫了範例,參考參考思路,能較快的整出來,就是有些配置比較蛋筒。

一開始選擇Plugin DevKit模式整的,都已經寫好,可是看官網文檔的時候,官方文檔開頭就說了:建議使用Gradle模式開發插件,又巴拉巴拉列了一堆好處;考慮良久,決定用Gradle模式重寫。框架

這個Gradle模式,最煩的仍是開頭新建項目的時候,那個Gradle死活下載不下來,科學全局上網都不行,而後手動下載了Gradle,指定本地Gradle,開全局再次同步時,會下載一個較大的社區版IDEA,可是使用本地Gradle加載完,存在一個很大的BUG!main文件夾下,不會自動生成Java文件夾!我真是佛了,點擊其它的文件夾,右擊:New -> Plugin DevKit 竟然不會沒有Action選項,差點把我勸退了,換了了七八個版本IDEA試了都不行!Action選項出不來,過了倆天后,晚上無心嘗試在main文件夾下面新建了一個Java文件,而後在這個java文件上右擊:New -> Plugin DevKit,Action選項出現了!真幾把佛了。。。less

還有個巨坑的問題,在Gradle模式下開發插件,把模板代碼文件放在main文件下、放在src下、放在根目錄下,都獲取不到文件裏面的內容,這個真是坑了我很多時間,搜了不少博客,都發現沒寫這個問題,官方文檔範例看了幾遍也沒發現有啥說明,後來找到了一個三年前的項目,翻了翻代碼發現,全部的資源文件都必須放在resources文件夾下,才能讀取到文件內容。。。我勒個去。。。

說明

  • 插件地址

  • 插件效果

    • 看下插件使用的效果圖吧,樣式參考了fish_redux插件樣式
    • 有一些可選擇的功能,因此作成多按鈕的樣式,你們能夠按照本身的需求進行操做
  • 說下插件的功能含義

    • Model:生成GetX的模式,

      • Default:默認模式,生成三個文件:state,logic,view
      • Easy:簡單模式,生成倆個文件:logic,view
    • Function:功能選擇

      • useFolder:使用文件,選擇後會生成文件夾,大駝峯命名自動轉換爲:小寫+下劃線
      • usePrefix:使用前綴,生成的文件前加上前綴,前綴爲:大駝峯命名自動轉換爲:小寫+下劃線
    • Module Name:模塊的名稱,請使用大駝峯命名

效果圖

  • 來看下使用的效果圖

getx_template

安裝

  • 在設置裏面選擇:Plugins ---> 輸入「getx」搜索 ---> 選擇名字爲:「GeX」 ---> 而後安裝 ---> 最後記得點擊下「Apply」
  • 若是在使用該插件的過程當中有什麼問題,請在該項目的github上給我提issue,我看到後,會盡快處理

image-20210130182527494

計數器

效果圖

counter_getx

實現

首頁,固然是實現一個簡單的計數器,來看GetX怎麼將邏輯層和界面層解耦的

  • 來使用插件生成下簡單文件

    • 模式選擇:Easy
    • 功能選擇:useFolder

image-20210126175019383

來看下生成的默認代碼,默認代碼十分簡單,詳細解釋放在倆種狀態管理裏

  • logic
import 'package:get/get.dart';

class CounterGetLogic extends GetxController {

}
  • view
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import 'logic.dart';

class CounterGetPage extends StatelessWidget {
  final CounterGetLogic logic = Get.put(CounterGetLogic());

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

響應式狀態管理

當數據源變化時,將自動執行刷新組件的方法
  • logic層

    • 由於是處理頁面邏輯的,加上Controller單詞過長,也防止和Flutter自帶的一些控件控制器弄混,因此該層用logic結尾,這裏就定爲了logic層,固然這點隨我的意向,寫Event,Controller都可
    • 這裏變量數值後寫.obs操做,是說明定義了該變量爲響應式變量,當該變量數值變化時,頁面的刷新方法將自動刷新;基礎類型,List,類均可以加.obs,使其變成響應式變量
class CounterGetLogic extends GetxController {
  var count = 0.obs;

  ///自增
  void increase() => ++count;
}
  • view層

    • 這地方獲取到Logic層的實例後,就可進行操做了,你們可能會想:WTF,爲何實例的操做放在build方法裏?逗我呢?--------- 實際否則,stl是無狀態組件,說明了他就不會被二次重組,因此實例操做只會被執行一次,並且Obx()方法是能夠刷新組件的,完美解決刷新組件問題了

      class CounterGetPage extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          CounterGetLogic logic = Get.put(CounterGetLogic());
      
          return Scaffold(
            appBar: AppBar(title: const Text('GetX計數器')),
            body: Center(
              child: Obx(
                () => Text('點擊了 ${logic.count.value} 次',
                    style: TextStyle(fontSize: 30.0)),
              ),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () => logic.increase(),
              child: const Icon(Icons.add),
            ),
          );
        }
      }
    • 固然,也能夠這樣寫

      class CounterGetPage extends StatelessWidget {
        final CounterGetLogic logic = Get.put(CounterGetLogic());
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(title: const Text('GetX計數器')),
            body: Center(
              child: Obx(
                () => Text('點擊了 ${logic.count.value} 次',
                    style: TextStyle(fontSize: 30.0)),
              ),
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () => logic.increase(),
              child: const Icon(Icons.add),
            ),
          );
        }
      }
    • 能夠發現刷新組件的方法極其簡單:Obx(),這樣能夠愉快的處處寫定點刷新操做了
  • Obx()方法刷新的條件

    • 只有當響應式變量的值發生變化時,纔會會執行刷新操做,當某個變量初始值爲:「test」,再賦值爲:「test」,並不會執行刷新操做
    • 當你定義了一個響應式變量,該響應式變量改變時,包裹該響應式變量的Obx()方法纔會執行刷新操做,其它的未包裹該響應式變量的Obx()方法並不會執行刷新操做,Cool!
  • 來看下若是把整個類對象設置成響應類型,如何實現更新操做呢?

    • 下面解釋來自官方README文檔
    • 這裏嘗試了下,將整個類對象設置爲響應類型,當你改變了類其中一個變量,而後執行更新操做,只要包裹了該響應類變量的Obx(),都會實行刷新操做,將整個類設置響應類型,須要結合實際場景使用
// model
// 咱們將使整個類成爲可觀察的,而不是每一個屬性。
class User() {
    User({this.name = '', this.age = 0});
    String name;
    int age;
}

// controller
final user = User().obs;
//當你須要更新user變量時。
user.update( (user) { // 這個參數是你要更新的類自己。
    user.name = 'Jonny';
    user.age = 18;
});
// 更新user變量的另外一種方式。
user(User(name: 'João', age: 35));

// view
Obx(()=> Text("Name ${user.value.name}: Age: ${user.value.age}"))
    // 你也能夠不使用.value來訪問模型值。
    user().name; // 注意是user變量,而不是類變量(首字母是小寫的)。

簡單狀態管理

GetBuilder:這是一個極其輕巧的狀態管理器,佔用資源極少!
  • logic:先來看看logic層
class CounterEasyGetLogic extends GetxController {
  var count = 0;

  void increase() {
    ++count;
    update();
  }
}
  • view
class CounterEasyGetPage extends StatelessWidget {
  final CounterEasyGetLogic logic = Get.put(CounterEasyGetLogic());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('計數器-簡單式')),
      body: Center(
        child: GetBuilder<CounterEasyGetLogic>(
          builder: (logicGet) => Text(
            '點擊了 ${logicGet.count} 次',
            style: TextStyle(fontSize: 30.0),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => logic.increase(),
        child: const Icon(Icons.add),
      ),
    );
  }
}
  • 分析下:GetBuilder這個方法

    • init:雖然上述代碼沒用到,可是,這個參數是存在在GetBuilder中的,由於在加載變量的時候就使用Get.put()生成了CounterEasyGetLogic對象,GetBuilder會自動查找該對象,因此,就能夠不使用init參數
    • builder:方法參數,擁有一個入參,類型即是GetBuilder所傳入泛型的類型
    • initState,dispose等:GetBuilder擁有StatefulWidget全部週期回調,能夠在相應回調內作一些操做

總結

分析

  • GetBuilder內部其實是對StatefulWidget的封裝,因此佔用資源極小
  • 響應式變量,由於使用的是StreamBuilder,會消耗必定資源

使用場景

  • 通常來講,對於大多數場景都是可使用響應式變量的
  • 可是,在一個包含了大量對象的List,都使用響應式變量,將生成大量的StreamBuilder,必將對內存形成較大的壓力,該狀況下,就要考慮使用簡單狀態管理了

跨頁面交互

跨頁面交互,在複雜的場景中,是很是重要的功能,來看看GetX怎麼實現跨頁面事件交互的

效果圖

  • 體驗一下
  • Cool,這纔是真正的跨頁面交互!下級頁面能隨意調用上級頁面事件,且關閉頁面後,下次重進,數據也很天然重置了(全局Bloc不會重置,須要手動重置)

jump_getx

實現

頁面一

常規代碼

  • logic

    • 這裏的自增事件,是供其它頁面調用的,該頁面自己沒使用
class JumpOneLogic extends GetxController {
  var count = 0.obs;

  ///跳轉到跨頁面
  void toJumpTwo() {
    Get.toNamed(RouteConfig.jumpTwo, arguments: {'msg': '我是上個頁面傳遞過來的數據'});
  }

  ///跳轉到跨頁面
  void increase() => count++;
}
  • view

    • 此處就一個顯示文字和跳轉功能
class JumpOnePage extends StatelessWidget {
  /// 使用Get.put()實例化你的類,使其對當下的全部子路由可用。
  final JumpOneLogic logic = Get.put(JumpOneLogic());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(title: Text('跨頁面-One')),
      floatingActionButton: FloatingActionButton(
        onPressed: () => logic.toJumpTwo(),
        child: const Icon(Icons.arrow_forward_outlined),
      ),
      body: Center(
        child: Obx(
          () => Text('跨頁面-Two點擊了 ${logic.count.value} 次',
              style: TextStyle(fontSize: 30.0)),
        ),
      ),
    );
  }
}

頁面二

這個頁面就是重點了

  • logic

    • 將演示怎麼調用前一個頁面的事件
    • 怎麼接收上個頁面數據
    • 請注意,GetxController包含比較完整的生命週期回調,能夠在onInit()接受傳遞的數據;若是接收的數據須要刷新到界面上,請在onReady回調裏面接收數據操做,onReady是在addPostFrameCallback回調中調用,刷新數據的操做在onReady進行,能保證界面是初始加載完畢後才進行頁面刷新操做的
class JumpTwoLogic extends GetxController {
  var count = 0.obs;
  var msg = ''.obs;

  @override
  void onReady() {
    var map = Get.arguments;
    msg.value = map['msg'];

    super.onReady();
  }

  ///跳轉到跨頁面
  void increase() => count++;
}
  • view

    • 加號的點擊事件,點擊時,能實現倆個頁面數據的變換
    • 重點來了,這裏經過Get.find(),獲取到了以前實例化GetXController,獲取某個模塊的GetXController後就很好作了,能夠經過這個GetXController去調用相應的事件,也能夠經過它,拿到該模塊的數據!
class JumpTwoPage extends StatelessWidget {
  final JumpOneLogic oneLogic = Get.find();
  final JumpTwoLogic twoLogic = Get.put(JumpTwoLogic());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(title: Text('跨頁面-Two')),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          oneLogic.increase();
          twoLogic.increase();
        },
        child: const Icon(Icons.add),
      ),
      body: Center(
        child: Column(mainAxisSize: MainAxisSize.min, children: [
          //計數顯示
          Obx(
            () => Text('跨頁面-Two點擊了 ${twoLogic.count.value} 次',
                style: TextStyle(fontSize: 30.0)),
          ),

          //傳遞數據
          Obx(
            () => Text('傳遞的數據:${twoLogic.msg.value}',
                style: TextStyle(fontSize: 30.0)),
          ),
        ]),
      ),
    );
  }
}

總結

GetX這種的跨頁面交互事件,真的是很是簡單了,侵入性也很是的低,不須要在主入口配置什麼,在複雜的業務場景下,這樣簡單的跨頁面交互方式,就能實現不少事了

進階吧!計數器

咱們可能會遇到過不少複雜的業務場景,在複雜的業務場景下,單單某個模塊關於變量的初始化操做可能就很是多,在這個時候,若是還將state(狀態層)和logic(邏輯層)寫在一塊兒,維護起來可能看的比較暈,這裏將狀態層和邏輯層進行一個拆分,這樣在稍微大一點的項目裏使用GetX,也能保證結構足夠清晰了!

在這裏就繼續用計數器舉例吧!

實現

此處須要劃分三個結構了:state(狀態層),logic(邏輯層),view(界面層)

  • 這裏使用插件生成下模板代碼

    • Model:選擇Default(默認)
    • Function:useFolder(默認中)

image-20210127093925934

來看下生成的模板代碼

  • state
class CounterHighGetState {
  CounterHighGetState() {
    ///Initialize variables
  }
}
  • logic
import 'package:get/get.dart';

import 'state.dart';

class CounterHighGetLogic extends GetxController {
  final state = CounterHighGetState();
}
  • view
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import 'logic.dart';
import 'state.dart';

class CounterHighGetPage extends StatelessWidget {
  final CounterHighGetLogic logic = Get.put(CounterHighGetLogic());
  final CounterHighGetState state = Get.find<CounterHighGetLogic>().state;

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

爲何寫成這樣三個模塊,須要把State單獨提出來,請速速瀏覽下方

改造

  • state

    • 這裏能夠發現,count類型使用的是RxInt,沒有使用var,使用該變量類型的緣由,此處是將全部的操做都放在構造函數裏面初始化,若是直接使用var沒有立馬賦值,是沒法推導爲Rx類型,因此這裏直接定義爲RxInt,實際很簡單,基礎類型將開頭字母大寫,而後加上Rx前綴便可
    • 實際上直接使用var也是能夠的,可是,使用該響應變量的時候.value沒法提示,須要本身手寫,因此仍是老老實實的寫明Rx具體類型吧
    • 詳細可查看:聲明響應式變量
class CounterHighGetState {
  RxInt count;

  CounterHighGetState() {
    count = 0.obs;
  }
}
  • logic

    • 邏輯層就比較簡單,須要注意的是:開始時須要實例化狀態類
class CounterHighGetLogic extends GetxController {
  final state = CounterHighGetState();

  ///自增
  void increase() => ++state.count;
}
  • view

    • 實際上view層,和以前的幾乎沒區別,區別的是把狀態層給獨立出來了
    • 由於CounterHighGetLogic被實例化,因此直接使用Get.find<CounterHighGetLogic>()就能拿到剛剛實例化的邏輯層,而後拿到state,使用單獨的變量接收下
    • ok,此時:logic只專一於觸發事件交互,state只專一數據
class CounterHighGetPage extends StatelessWidget {
  final CounterHighGetLogic logic = Get.put(CounterHighGetLogic());
  final CounterHighGetState state = Get.find<CounterHighGetLogic>().state;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('計數器-響應式')),
      body: Center(
        child: Obx(
              () => Text('點擊了 ${state.count.value} 次',
              style: TextStyle(fontSize: 30.0)),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => logic.increase(),
        child: const Icon(Icons.add),
      ),
    );
  }
}

對比

看了上面的改造,屏幕前的你可能想吐槽了:坑比啊,以前簡簡單單的邏輯層,被拆成倆個,還搞得這麼麻煩,你是猴子請來的逗比嗎?

你們先別急着吐槽,當業務過於複雜,state層,也是會維護不少東西的,讓咱們看看下面的一個小栗子,下面實例代碼是不能直接運行的,想看詳細運行代碼,請查看項目:flutter_use

  • state
class MainState {
  ///選擇index - 響應式
  RxInt selectedIndex;

  ///控制是否展開 - 響應式
  RxBool isUnfold;

  ///分類按鈕數據源
  List<BtnInfo> list;

  ///Navigation的item信息
  List<BtnInfo> itemList;

  ///PageView頁面
  List<Widget> pageList;
  PageController pageController;

  MainState() {
    //初始化index
    selectedIndex = 0.obs;
    //默認不展開
    isUnfold = false.obs;
    //PageView頁面
    pageList = [
      keepAliveWrapper(FunctionPage()),
      keepAliveWrapper(ExamplePage()),
      keepAliveWrapper(Center(child: Container())),
    ];
    //item欄目
    itemList = [
      BtnInfo(
        title: "功能",
        icon: Icon(Icons.bubble_chart),
      ),
      BtnInfo(
        title: "範例",
        icon: Icon(Icons.opacity),
      ),
      BtnInfo(
        title: "設置",
        icon: Icon(Icons.settings),
      ),
    ];
    //頁面控制器
    pageController = PageController();
  }
}
  • logic
class MainLogic extends GetxController {
  final state = MainState();

  ///切換tab
  void switchTap(int index) {
    state.selectedIndex.value = index;
  }

  ///是否展開側邊欄
  void onUnfold(bool unfold) {
    state.isUnfold.value = !state.isUnfold.value;
  }
}
  • view
class MainPage extends StatelessWidget {
  final MainLogic logic = Get.put(MainLogic());
  final MainState state = Get.find<MainLogic>().state;

  @override
  Widget build(BuildContext context) {
    return BaseScaffold(
      backgroundColor: Colors.white,
      body: Row(children: [
        ///側邊欄區域
        Obx(
          () => SideNavigation(
            selectedIndex: state.selectedIndex.value,
            sideItems: state.itemList,
            onItem: (index) {
              logic.switchTap(index);
              state.pageController.jumpToPage(index);
            },
            isUnfold: state.isUnfold.value,
            onUnfold: (unfold) {
              logic.onUnfold(unfold);
            },
          ),
        ),

        ///Expanded佔滿剩下的空間
        Expanded(
          child: PageView.builder(
            physics: NeverScrollableScrollPhysics(),
            itemCount: state.pageList.length,
            itemBuilder: (context, index) => state.pageList[index],
            controller: state.pageController,
          ),
        )
      ]),
    );
  }
}

從上面能夠看出,state層裏面的狀態已經較多了,當某些模塊涉及到大量的:提交表單數據,跳轉數據,展現數據等等,state層的代碼會至關的多,相信我,真的是很是多,一旦業務發生變動,還要常常維護修改,就蛋筒了

在複雜的業務下,將狀態層(state)和業務邏輯層(logic)分開,絕對是個明智的舉動

最後

  • 該模塊的效果圖就不放了,和上面計數器效果如出一轍,想體驗一下,可點擊:體驗一下
  • 簡單的業務模塊,可使用倆層結構:logic,view;複雜的業務模塊,推薦使用三層結構:state,logic,view

路由管理

GetX實現了一套用起來十分簡單的路由管理,可使用一種極其簡單的方式導航,也可使用命名路由導航

簡單路由

  • 主入口配置
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: MainPage(),
    );
  }
}
  • 路由的相關使用

    • 使用是很是簡單,使用Get.to()之類api便可,此處簡單演示,詳細api說明,放在本節結尾
//跳轉新頁面
Get.to(SomePage());

命名路由導航

這裏是推薦使用命名路由導航的方式

  • 統一管理起了全部頁面
  • 在app中可能感覺不到,可是在web端,加載頁面的url地址就是命名路由你所設置字符串,也就是說,在web中,能夠直接經過url導航到相關頁面

下面說明下,如何使用

  • 首先,在主入口出配置下
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      initialRoute: RouteConfig.main,
      getPages: RouteConfig.getPages,
    );
  }
}
  • RouteConfig類

    • 下面是個人相關頁面,和其映射的頁面,請根據本身的頁面進行相關編寫
class RouteConfig{
  ///主頁面
  static final String main = "/";

  ///dialog頁面
  static final String dialog = "/dialog";

  ///bloc計數器模塊
  static final String counter = "/counter";

  ///測試佈局頁面
  static final String testLayout = "/testLayout";

  ///演示SmartDialog控件
  static final String smartDialog = "/smartDialog";

  ///Bloc跨頁面傳遞事件
  static final String spanOne = "/spanOne";
  static final String spanTwo = "/spanOne/spanTwo";

  ///GetX 計數器  跨頁面交互
  static final String counterGet = "/counterGet";
  static final String jumpOne = "/jumpOne";
  static final String jumpTwo = "/jumpOne/jumpTwo";

  ///別名映射頁面
  static final List<GetPage> getPages = [
    GetPage(name: main, page: () => MainPage()),
    GetPage(name: dialog, page: () => Dialog()),
    GetPage(name: counter, page: () => CounterPage()),
    GetPage(name: testLayout, page: () => TestLayoutPage()),
    GetPage(name: smartDialog, page: () => SmartDialogPage()),
    GetPage(name: spanOne, page: () => SpanOnePage()),
    GetPage(name: spanTwo, page: () => SpanTwoPage()),
    GetPage(name: counterGet, page: () => CounterGetPage()),
    GetPage(name: jumpOne, page: () => JumpOnePage()),
    GetPage(name: jumpTwo, page: () => JumpTwoPage()),
  ];
}

路由API

請注意命名路由,只須要在api結尾加上Named便可,舉例:

  • 默認:Get.to(SomePage());
  • 命名路由:Get.toNamed(「/somePage」);

詳細Api介紹,下面內容來自GetX的README文檔,進行了相關整理

  • 導航到新的頁面
Get.to(NextScreen());
Get.toNamed("/NextScreen");
  • 關閉SnackBars、Dialogs、BottomSheets或任何你一般會用Navigator.pop(context)關閉的東西
Get.back();
  • 進入下一個頁面,但沒有返回上一個頁面的選項(用於SplashScreens,登陸頁面等)
Get.off(NextScreen());
Get.offNamed("/NextScreen");
  • 進入下一個界面並取消以前的全部路由(在購物車、投票和測試中頗有用)
Get.offAll(NextScreen());
Get.offAllNamed("/NextScreen");
  • 發送數據到其它頁面

只要發送你想要的參數便可。Get在這裏接受任何東西,不管是一個字符串,一個Map,一個List,甚至一個類的實例。

Get.to(NextScreen(), arguments: 'Get is the best');
Get.toNamed("/NextScreen", arguments: 'Get is the best');

在你的類或控制器上:

print(Get.arguments);
//print out: Get is the best
  • 要導航到下一條路由,並在返回後當即接收或更新數據
var data = await Get.to(Payment());
var data = await Get.toNamed("/payment");
  • 在另外一個頁面上,發送前一個路由的數據
Get.back(result: 'success');
// 並使用它,例:
if(data == 'success') madeAnything();
  • 若是你不想使用GetX語法,只要把 Navigator(大寫)改爲 navigator(小寫),你就能夠擁有標準導航的全部功能,而不須要使用context,例如:
// 默認的Flutter導航
Navigator.of(context).push(
  context,
  MaterialPageRoute(
    builder: (BuildContext context) {
      return HomePage();
    },
  ),
);

// 使用Flutter語法得到,而不須要context。
navigator.push(
  MaterialPageRoute(
    builder: (_) {
      return HomePage();
    },
  ),
);

// get語法
Get.to(HomePage());

動態網頁連接

  • 這是一個很是重要的功能,在web端,能夠保證經過url傳參數到頁面

Get提供高級動態URL,就像在Web上同樣。Web開發者可能已經在Flutter上想要這個功能了,Get也解決了這個問題。

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

在你的controller/bloc/stateful/stateless類上:

print(Get.parameters['id']);
// out: 354
print(Get.parameters['name']);
// out: Enzo

你也能夠用Get輕鬆接收NamedParameters。

void main() {
  runApp(
    GetMaterialApp(
      initialRoute: '/',
      getPages: [
      GetPage(
        name: '/',
        page: () => MyHomePage(),
      ),
      GetPage(
        name: '/profile/',
        page: () => MyProfile(),
      ),
       //你能夠爲有參數的路由定義一個不一樣的頁面,也能夠爲沒有參數的路由定義一個不一樣的頁面,可是你必須在不接收參數的路由上使用斜槓"/",就像上面說的那樣。
       GetPage(
        name: '/profile/:user',
        page: () => UserProfile(),
      ),
      GetPage(
        name: '/third',
        page: () => Third(),
        transition: Transition.cupertino  
      ),
     ],
    )
  );
}

發送命名路由數據

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

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

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

如今,你須要作的就是使用Get.toNamed()來導航你的命名路由,不須要任何context(你能夠直接從你的BLoC或Controller類中調用你的路由),當你的應用程序被編譯到web時,你的路由將出如今URL中。

最後

相關地址

系列文章

引流了,手動滑稽.jpg
相關文章
相關標籤/搜索