Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Frank1016/flutter-getx-template

Open more actions menu
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

flutter_getx_template

Language: 中文简体 | English

visitors null safety flutter version getx version

基于getx 实现的全新flutter getx 模版,适用于中大型项目的开发。

  • 💥 flutter最新版本的空安全
  • 🍀 view逻辑 完全解耦
  • viewstate 自动响应
  • 📦 dioshared_preferences等通用模块的封装
  • 🔥 去context

环境

Flutter 2.2.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision b22742018b (3 weeks ago) • 2021-05-14 19:12:57 -0700
Engine • revision a9d88a4d18
Tools • Dart 2.13.0

lib目录划分

  • common

此目录用来存放通用模块及其变量,例如colorslangsvalues等,例如:

├── colors
│   └── colors.dart
├── langs
│   ├── en_US.dart
│   ├── translation_service.dart
│   └── zh_Hans.dart
└── values
    ├── cache.dart
    ├── storage.dart
    └── values.dart
  
  • components

此目录主要存放顶层公告组件,例如 appbarscaffolddialog等等,例如:

├── components.dart
├── custom_appbar.dart
└── custom_scaffold.dart
  • pages

此目录主要存放页面文件,例如:

注:每个Item为一个文件夹.

├── Index
├── home
├── login
├── notfound
├── proxy
└── splash

  • router

此目录为路由文件,此模版的路由方式约定为命名路由,为固定目录,目录结构如下:

├── app_pages.dart
└── app_routes.dart

  • services

此目录用来存放API,例如:

├── services.dart
└── user.dart  // 关于用户的API
  • utils

此目录用来存放一些工具模块,例如 requestlocal_storage等等,例如:

├── authentication.dart
├── local_storage.dart
├── request.dart
├── screen_device.dart
└── utils.dart

开发规范

当你需要新建一个页面时,你需要按照以下步骤进行:

假设我们现在要创建一个Home 页面.

  1. pages 目录下新建home 目录:
// pages

$ mkdir home
$ cd home
  1. home 目录下,新建以下四个文件:
  • home_view.dart : 视图(用来实现页面布局)

  • home_contrller.dart : 控制器(用来实现业务逻辑)

  • home_binding : 控制器绑定(用来绑定controllerview)

  • home_model : 数据模型(用来约定数据模型)

注意:每创建一个页面时,都必须如此做,命名采用 '页面名_key' 这样的形式。

当你创建好一个页面,目录应该长这样👇:

// home
.
├── home.binding.dart
├── home_controller.dart
├── home_model.dart
└── home_view.dart
  1. router文件夹下面添加对应路由:
// app_routes.dart
part of 'app_pages.dart';
abstract class AppRoutes {
  ...
  static const Home = '/home';
  ...
}
// app_pages.dart
class AppPages {

  static final routes = [
    ...
    GetPage(
      name: AppRoutes.Home,
      page: () => HomePage(),
      binding: HomeBinding(),
    ),
    ...
  ];
}

完成以上步骤,你就可以愉快的开始开发了。

状态管理

contrller 是我们实现业务逻辑的地方,为什么我们要将 业务逻辑和视图分开呢?因为flutter 的意大利面式的代码实在是太难维护了,本来flutter 的页面布局和样式写在一起就很恶心了,再加上业务逻辑代码的话,实在太难以维护,而且,如果我们想要拥有状态的话,我们的页面不得不继承自stateful widget,性能损耗太严重了。

所以我们利用 getx 提供的 controller,将我们的业务逻辑和视图解耦。

一个标准的contrller长这样:

class HomeController extends GetxController {
  final count = 0.obs;

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

  @override
  void onReady() {}

  @override
  void onClose() {}

  void increment() => count.value++;
}

当我们需要一个响应式的变量时,我们只需在变量的后面加一个.obs,例如:

final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
final balance = 0.0.obs;
final number = 0.obs;
final items = <String>[].obs;
final myMap = <String, int>{}.obs;

// 甚至自定义类 - 可以是任何类
final user = User().obs;

值得注意的是,因为现在flutter 有了null-safety,所以我们最好给响应式变量一个初始值。

当我们在controller更新了响应式变量时,视图会自动更新渲染。

但是实际上,你也可以不定义这种响应式变量,例如我们可以这样:

class HomeController extends GetxController {
  int count = 0;

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

  @override
  void onReady() {}

  @override
  void onClose() {}

  void increment() {
    count++;
    update();
  } 
}

这样和.obs的唯一区别是,我们需要手动调用 update() 更新状态的变化,这样view才能在count变化时,收到我们的通知重新渲染。

我们应该将发起请求,放在onInit钩子里面,例如进入订单页面时,我们应该获取订单信息,就如同在 stateful wdiget 里面的init钩子一样。

视图

首先,你需要将你的class 继承自 GetxView<T>(T 为你的Controller),例如:

class HomePage extends GetView<HomeController> {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(),
    );
  }
}

GetxView<HomeController> 会自动帮你把 Controller 注入到 view 中,你可以简单理解为它自动帮你执行了以下步骤

final controller = Get.find<HomeController>();

不必担心 GetxView<T> 的性能,因为它仅仅是继承自 Stateless Widget ,记住,有了 getx 你完全不需要 Stateful Widget

当我们想要绑定controller的变量时,我们约定了两种方法:

  1. Obx(()=>)

如果你的变量是.obs的,那么我们就使用Obx(()=>),它会在变量变更时自动刷新view,例如:

// home_contrller
class HomeController extends GetxController {
  final count = 0.obs;

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

  @override
  void onReady() {}

  @override
  void onClose() {}

  void increment() => count.value++;
}

view里面使用 Obx(()=>) 绑定count:

// home_view
class HomePage extends GetView<HomeController> {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Obx(() => Center(child: Text(controller.count.toString()))),
      ),
    );
  }
}
  1. GetBuilder<T>

如果你的变量不是.obs的,那么我们就使用GetBuilder<T>,例如:

class HomeController extends GetxController {
  int count = 0;

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

  @override
  void onReady() {}

  @override
  void onClose() {}

  void increment() {
    count++;
    update();
  } 
}

view 里面使用 GetBuilder<T> 绑定count:

class HomePage extends GetView<HomeController> {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BaseScaffold(
      appBar: MyAppBar(
        centerTitle: true,
        title: MyTitle('首页'),
        leadingType: AppBarBackType.None,
      ),
      body: Container(
        child: GetBuilder<HomeController>(builder: (_) {
          return Center(child: Text(controller.count.toString()));
        }),
      ),
    );
  }
}

其实getx还提供了其他的render function,但是为了减少心智负担和复杂度,我们就使用这两种就够了。

路由管理

这里我们采用了getx提供的命名式路由,如果你学过vue,那么几乎没有学习成本。

假设我们现在添加了一个页面,叫做List,然后我们需要到router文件夹下面去配置它:

// app_routes.dart
part of 'app_pages.dart';
abstract class AppRoutes {
  ...
  static const List = '/list';
  ...
}
// app_pages.dart
class AppPages {

  static final routes = [
    ...
    GetPage(
      name: AppRoutes.Home,
      page: () => ListPage(),
      binding: ListBinding(),
    ),
    ...
  ];
}

这个List对应的假设是订单列表,当我们点击列表中某个订单时,我们通常会进入到订单详情页面,所以我们此时应再添加一个详情页面:

// app_routes.dart
part of 'app_pages.dart';
abstract class AppRoutes {
  ...
  static const List = '/list';
  static const Detaul = '/detail';
  ...
}
// app_pages.dart
class AppPages {

  static final routes = [
    ...
    GetPage(
      name: AppRoutes.Home,
      page: () => ListPage(),
      binding: ListBinding(),
      children: [
        GetPage(
          name: AppRoutes.Detail,
          page: () => DetailPage(),
          binding: DetailBinding(),
        ),
      ],
    ),
    ...
  ];
}

因为详情页面和列表页面有先后级关系,所以我们可以将 Detail 页面,放到 Listchildren 下面,当然你也可以不这样做。

当我们使用时:

Get.toNamed('/list/detail');

其他路由钩子:

浏览并删除前一个页面:

Get.offNamed("/NextScreen");

浏览并删除所有以前的页面:

Get.offAllNamed("/NextScreen");

传递参数:

Get.toNamed("/NextScreen", arguments: {id: 'xxx'});

参数的类型可以是一个字符串,一个Map,一个List,甚至一个类的实例。

获取参数:

print(Get.arguments);
// print out: `{id: 'xxx'}`

使用 getx 的路由它有一个非常好的优点,那就是它是去context化的。还记得我们以前被context 支配的恐惧吗? 有了getx,它将不复存在。

使用 monia-cli 进行开发

我们很高兴,能将 flutter-getx-template 加入到 monia-cli

利用 monia-cli 新建flutter项目:

monia create <project-name>
➜  Desktop monia create flutter_demo
? Which framework do you want to create Flutter
? Which flutter version do you want to create null-safety
? Please input your project description description
? Please input project version 1.0.0

✨  Creating project in /Users/xieyezi/Desktop/flutter_demo.

🗃  Initializing git repository....
.......
⠏ Download template from monia git repository... This might take a while....

🎉  Successfully created project flutter_demo.
👉  Get started with the following commands:

$ cd flutter_demo
$ flutter run

                        _                  _ _ 
  _ __ ___   ___  _ __ (_) __ _        ___| (_)
 | '_ ` _ \ / _ \| '_ \| |/ _` |_____ / __| | |
 | | | | | | (_) | | | | | (_| |_____| (__| | |
 |_| |_| |_|\___/|_| |_|_|\__,_|      \___|_|_|

不仅如此, monia-cli 还提供了快速生成一个 flutter getx 页面的功能。

假如现在你想生成一个 order_sending 新页面,你只需在 pages 目录下面输入:

monia init order_sending
➜  pages monia init order_sending
✨  Generate page in /Users/xieyezi/Desktop/flutter_demo/lib/pages/order_sending.
⠋ Generating, it's will not be wait long...
generate order_sending lib success.
generate /Users/xieyezi/Desktop/flutter_demo/lib/pages/order_sending/order_sending_view.dart file success.
generate /Users/xieyezi/Desktop/flutter_demo/lib/pages/order_sending/order_sending_controller.dart file success.
generate /Users/xieyezi/Desktop/flutter_demo/lib/pages/order_sending/order_sending_binding.dart file success.

🎉  Successfully generate page order_sending.

vscode 插件

monia 还提供了vscode 插件: monia-vscode-extension

点击左下角的monia-generate 文字按钮,输入pageName,即可在pages目录下新建一个flutter getx page

example.gif

官方链接

状态管理 路由管理 依赖管理

About

flutter 2.x and getx v4.x template

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Dart 84.6%
  • HTML 10.1%
  • Ruby 3.7%
  • Swift 1.1%
  • Other 0.5%
Morty Proxy This is a proxified and sanitized view of the page, visit original site.