Warehouse address: github.com/xieyezi/flu…

Said in the previous

Hi, long time no see, this time I bring a practical article about Flutter + getx.

The new Flutter GetX template, based on getX implementation, is suitable for medium to large project development.

  • 💥 flutterLatest version of air security
  • 🍀 viewlogicCompletely decoupled
  • viewstateAutomatic response
  • 📦 dio,shared_preferencesAnd other general module encapsulation
  • 🔥 tocontextthe

The environment

Flutter 2.2.0, channel stable, https://github.com/flutter/flutter.git Framework, revision b22742018b (3 weekes line) Engine • Revision A9D88A4D18 Tools • Dart 2.13.0Copy the code

Lib directory partition

  • common

This directory is used to store generic modules and their variables, such as colors, Langs, values, etc., for example:

├── bass exercises ── bass exercises ── bass exercises ── bass exercises ── bass exercises ── bass Exercises ── ├── lessons.├ ─ lessons.├Copy the code
  • components

This directory mainly houses the top-level bulletin components such as AppBar, scaffold, Dialog, etc. For example:

├── ├─ Bass exercises ── Bass exercisesCopy the code
  • pages

This directory mainly stores page files, for example:

Note: Each Item is a folder.

├─ Index ├─ home ├─ login ├─ proxy ├─ splashCopy the code
  • router

This directory is a routing file. The routing mode convention of this template is named route, which is a fixed directory. The directory structure is as follows:

├ ─ ─ app_pages. Dart └ ─ ─ app_routes. The dartCopy the code
  • services

This directory is used to store apis such as:

├─ services. ├─ user //Copy the code
  • utils

This directory is used to store utility modules such as request, local_storage, etc., for example:

├── Authentication.Bass Exercises ── ├─ Authentication.bass Exercises ── Bass.Bass Exercises ── Bass.bass ExercisesCopy the code

The development of specification

When you need to create a new page, you need to follow these steps:

Suppose we now want to create a Home page.

  1. inpagesCreating a DirectoryhomeDirectory:
// pages

$ mkdir home
$ cd home
Copy the code
  1. inhomeUnder the directory, create the following four files:
  • Home_view.dart: view (for page layout)

  • Home_contrler. dart: controller (used to implement business logic)

  • Home_binding: controller binding (used to bind controller to view)

  • Home_model: data model (used to contract data models)

Note: this must be done every time a page is created, with the form ‘page name_key’.

When you have created a page, the directory should look like 👇 :

/ / home. ├ ─ ─ home. Binding. The dart ├ ─ ─ home_controller. Dart ├ ─ ─ home_model. Dart └ ─ ─ home_view. The dartCopy the code
  1. torouterAdd route to folder:
// app_routes.dart
part of 'app_pages.dart';
abstract class AppRoutes {...static const Home = '/home'; . }Copy the code
// app_pages.dart
class AppPages {

  static finalroutes = [ ... GetPage( name: AppRoutes.Home, page: () => HomePage(), binding: HomeBinding(), ), ... ] ; }Copy the code

Complete the steps above, and you’ll be happy to start developing.

State management

Contrller is where we implement our business logic, so why do we separate business logic from view? Because the spaghetti code of flutter was too difficult to maintain, the layout and style of a flutter page were disgusting, and the business logic code was too difficult to maintain. Moreover, if we wanted to have state, our pages had to inherit from stateful widgets. There is too much performance loss.

So we use the Controller provided by GetX to decouple our business logic from our view.

A standard Contrller looks like this:

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

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

  @override
  void onReady() {}

  @override
  void onClose() {}

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

When we need a responsive variable, we simply add a. Obs to the end of the variable, for example:

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;

// Even custom classes - can be any class
final user = User().obs;
Copy the code

Note that since the flutter now has null-safety, it is best to give the response variable an initial value.

When we update the reactive variable in controller, the view automatically updates the render.

But in practice, you don’t have to define reactive variables, for example:

class HomeController extends GetxController {
  int count = 0;

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

  @override
  void onReady() {}

  @override
  void onClose() {}

  voidincrement() { count++; update(); }}Copy the code

The only difference between this and.obs is that we need to manually call update() to update the state change so that the view can be notified to rerender when the count changes.

We could put the request into an onInit hook, so for example, we could get the order information when we went to the order page, just like the init hook in stateful Wdiget.

view

First, you need to inherit your class from GetxView

(T is your Controller), for example:

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

  @override
  Widget build(BuildContext context) {
    returnScaffold( body: Container(), ); }}Copy the code

GetxView

will automatically inject Controller into the view for you. You can simply say that it automatically does the following for you

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

Don’t worry about the performance of GetxView

because it simply inherits the Stateless Widget. Remember, with GetX you don’t need Stateful widgets at all

When we want to bind controller variables, we agree on two methods:

  1. Obx(()=>)

If your variable is.obs, then we use Obx(()=>), which automatically refreshes the view when the variable changes, for example:

// 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++;
}
Copy the code

Use Obx(()=>) to bind count inside view:

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

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

If your variable is not.obs, then we use GetBuilder

, for example:

class HomeController extends GetxController {
  int count = 0;

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

  @override
  void onReady() {}

  @override
  void onClose() {}

  voidincrement() { count++; update(); }}Copy the code

Use GetBuilder

to bind count in the view:

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

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

Getx provides other render functions as well, but to reduce the mental burden and complexity, these two will suffice.

Routing management

Here we use the named routing provided by GetX, and if you have learned VUE, there is almost no learning cost.

Suppose we now add a page called List, and we need to configure it under the Router folder:

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

  static finalroutes = [ ... GetPage( name: AppRoutes.Home, page: () => ListPage(), binding: ListBinding(), ), ... ] ; }Copy the code

The assumption corresponding to this List is the order List. When we click an order in the List, we will usually enter the order detail page, so we should add another detail page at this time:

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

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

Because the Detail page and the List page have a hierarchy, we can put the Detail page under the children in the List, but you don’t have to do that.

When we use:

Get.toNamed('/list/detail');
Copy the code

Other routing hooks:

Browse and delete the previous page:

Get.offNamed("/NextScreen");
Copy the code

Browse and delete all previous pages:

Get.offAllNamed("/NextScreen");
Copy the code

Pass parameters:

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

The type of the argument can be a string, a Map, a List, or even an instance of a class.

Get parameters:

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

Route using getx it has a nice advantage that it is contextualized. Remember how we used to fear being dominated by context? With GetX, it will cease to exist.

usemonia-cliTo develop

We are happy to add flutter- gex-Template to monia-CLI.

Create a Flutter project using monia-CLI:

monia create <project-name>
Copy the code
➜ 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 ? Both Please input the 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 _ _ _ _ __ ___ ___ _ __ (_) __ _ ___| (_) | '_ ` _ \ / _ \| '_ \| |/ _` |_____ / __| | | | | | | | | (_) | | | | | (_ | | | _____ (__ | | | | _ | | _ | | _ | \ ___ / | _ | | _ _ - | | \ __, _ | \ ___ | _ _ - | |Copy the code

Not only that, monia-CLI also provides the ability to quickly generate a Flutter Getx page.

If you now want to generate a new order_sending page, you simply type under the Pages directory:

monia init order_sending
Copy the code
➜ 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.Copy the code

Vscode plug-in

Monia also provides the vscode plug-in: monia-vscode-extension

Create a Flutter getx Page in the Pages directory by clicking on the monia-generate text button in the lower left corner and entering pageName:

The official link

Status management Route management dependency management