【第十一天 - Flutter GetX 架构教学】

前言

今日的程序码 => GIHUB

GetX 介绍

GetX 官方文件

GetX 是一个很神奇的状态管理,里面有路由、语言、网路、还有一些内建的方法。我个人觉得他可以使用简短的程序码,达到想要的效果。可以看到下面的这几张图片。
NavigationDialogSnackBar、便利的资料传递、快速的储存资料、简单的国际化语言、简单的改片 App 颜色、快速的验证。
他可以快速的分享资料、状态等资讯,因此他很强大。
https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png
图片来源 => https://raw.githubusercontent.com/jonataslaw/getx-community/master/getx.png

优势

  • 可以不用写 StreamController
  • 不需要为一个初始值建立一个 get
  • 不同页面之间共享状态
  • 可以使用 StatelessWidget 节省一些记忆体,使用 Get 你可能不再需要使用 StatefulWidget
  • 有许多内建的方法可以直接使用

缺点

  • 个人觉得他里面包了太多神奇的东西,哪一天 flutter 改版了一下,GetX 可能就需要一些时间更新了
  • 小型专案很适合,可是大型专案,可能需要一些测试等等,因此可能会不太适合(ㄅ)
  • 会被 GetX 绑住

以上是小弟的见解,有误,欢迎留言底下和我说~~

先来介绍 Api Service 的部分

首先 Model 的部分可以参考 【第七天 - Flutter Api、Json 物件教学】

GetConnect

GetConnect 是一个 GetX 提供给 Api 请求资料的一个类别。因此不需要去使用 Http 的套件了。

class PostService extends GetConnect {
//  请求 Api
  Future<List<PostModel>> fetchData() async {
    return await get(
      'https://jsonplaceholder.typicode.com/posts',
      decoder: (data) =>
      List<PostModel>.from(data.map((e) => PostModel.fromJson(e))),
    ).then((value) => value.body!).catchError((e) => throw e);
  }
}

GetxController 控制器

GetxController 是一个控制器,我们继承他,就可以操作了。也不用把他想的那麽复杂。

.obs 的话,代表我们可以观察那笔资料。当我们使用 update() 就可以通知画面我们更新数据了。

enum SortState { userID, id, title, body }

class PostController extends GetxController {
  var isLoading = true.obs;
  var postList = <PostModel>[].obs;

  @override
  void onInit() {
    super.onInit();
    fetchApi();
  }

  void fetchApi() async {
    isLoading(true);
    await PostService().fetchData().then((value) {
      postList.assignAll(value);
      isLoading(false);
      update();
    }).catchError((e) {});
  }

  // sort method
  void sort(SortState sortState) async {
    switch (sortState) {
      case SortState.title:
        postList.sort((a, b) => a.title.compareTo(b.title));
        break;
      case SortState.id:
        postList.sort((a, b) => a.id.compareTo(b.id));
        break;
      case SortState.userID:
        postList.sort((a, b) => a.userId.compareTo(b.userId));
        break;
      case SortState.body:
        postList.sort((a, b) => a.body.compareTo(b.body));
        break;
    }
    update();
  }
}

使用方式

如果资料都有 .obs 的话,我们在 UI 的部分就可以直接 body: Obx(() => Widget) 的方式直接拿到数据。

初始化 controller 使你其对当下的所有子路由可用。

final PostController controller = Get.put(PostController());

你可以找到一个正在被其他页面使用的 Controller

Get.find<PostController>().sort(value);

View(画面、UI)

HomePage

class HomePage extends StatelessWidget {
  HomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  final PostController controller = Get.put(PostController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
        actions: <Widget>[
          PopupMenuButton<SortState>(
            icon: Icon(Icons.more_vert),
            itemBuilder: (context) => [
              PopupMenuItem(
                child: Text('使用 userId 排序'),
                value: SortState.userID,
              ),
              PopupMenuItem(
                child: Text('使用 id 排序'),
                value: SortState.id,
              ),
              PopupMenuItem(
                child: Text('使用 title 排序'),
                value: SortState.title,
              ),
              PopupMenuItem(
                child: Text('使用 body 排序'),
                value: SortState.body,
              )
            ],
            onSelected: (SortState value) {
              Get.find<PostController>().sort(value);
            },
          )
        ],
      ),
      body: _MyListView()
    );
  }
}

_MyListView

class _MyListView extends StatelessWidget {
   _MyListView({Key? key}) : super(key: key);
  final PostController controller = Get.find<PostController>();
  @override
  Widget build(BuildContext context) {
    return Obx(() => controller.isLoading.value
        ? Center(child: CircularProgressIndicator())
        : ListView.builder(
      itemCount: controller.postList.length,
      itemBuilder: (context, index) {
        PostModel item = controller.postList[index];
        return Container(
            decoration: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(16)),
                color: Colors.white,
                border:
                Border.all(color: Colors.blueAccent, width: 2.0)),
            margin: EdgeInsets.all(8),
            padding: EdgeInsets.all(8),
            child: RichText(
              text: TextSpan(
                style: DefaultTextStyle.of(context).style,
                children: <TextSpan>[
                  TextSpan(
                    text: item.id.toString() + ". " + item.title,
                    style: TextStyle(fontSize: 18, color: Colors.red),
                  ),
                  TextSpan(
                    text: '\n' + item.body,
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                  TextSpan(
                    text: "\nUser ID:" + item.userId.toString(),
                    style: TextStyle(fontSize: 18),
                  ),
                ],
              ),
            ));
      },
    ));
  }
}

<<:  【设计+切版30天实作】|Day11 - [设计进阶挑战] 如何把Reviews的呈现方式改成可滚动式的卡片呢?

>>:  AI ninja project [day 25] QLattice -- 基础分类

Day 30 工作排程与打包

30天的旅程就要在这边画上句点罗~ 今天的影片内容为介绍两个实用的辅助工具—工作排程器与pyinst...

[Day 1]-前言

铁人赛来到了第13届,作为资讯人,在这次参赛之前,我也透过铁人赛学习到许多,但直到现在,我才鼓起勇气...

Rust-结构体(Struct)

struct 是命名并封装数个栏位数值所组合的自订型别 struct 有 3 种类型 元组结构体(t...

Day 20:AWS 是什麽?30天从动漫/影视作品看AWS服务应用 -《龙与雀斑公主》

大家好像纷纷完赛我还在这边混,不满三十篇真的要一语成谶了QQ 未来也许会转移到其他平台去继续写一些关...

Day 2 Flutter介绍

Flutter架构 (一)Framework:由纯Dart语言实现的SDK 1.底下两层:底层UI函...