preface

This article does not write the use of getX framework, and its code to generate IDEA plug-in functions explained

I’ve written two long getX articles before

An introduction to the use of Flutter GetX – The charm of simplicity!

A principle of depth profiling: Flutter GetX depth profiling | we will out of my way (word graphic)

Fish and fishing have been handed over to everyone, there is no need to belabor

I also wrote a getX code generation plugin: getx_Template, which is the equivalent of a fishing chair (more comfortable fishing or eating fish?). !!!! The initial function is very simple, is to generate a single page corresponding module code, even a memory option function, basically is a plastic seat

  • But with a lot ofDiao hair handsomeGiven my various requirements, the plugin has become a bit complicated
  • Especially when it comes to the Select Function module, some people may not understand the meaning of the selected Function button.
  • So, this phoenix young want to detail, and you wolong talk about this tool all aspects of the function, I hope to help you save some development time

Guys, I really don’t want to write about hydrology; But this tool a function button, the change of the code may be very little, its behind the implied things, may need a lot of ink to describe, here on the unity and you yanzuzuyu Yifei, said.

This article has been updated for a long time, but if you want to know the details of each plugin update, you can click here to see it.

Code generation

  • Just search for getx in Plugins

contrast

  • Early code generation pop-ups had few options, and persistent storage was not supported
    • Heck, the icon is ugly

  • This is the feature selection popover after many refinements

I am a complete appearance level party, the latest version of the page, I did a lot of considerations

  • With the various needs of you, Select Function has been increased from the original two functions to the present seven functions

    • As more function buttons are laid flat on the Dialog, the entire dialog becomes considerably longer in height
    • The most important thing is: it will make the user unclear what the key Function button in Function is!
  • Based on the above thinking, I racked my brains to solve this problem

    • Plan 1: I originally wanted to make a folding storage area, and the secondary function buttons were placed in the folding area
      • Swing after a write, found that the effect is really ugly, when receiving, height calculation also has problems: give up
    • Plan 2: This is when I flip swing controls, foundJBTabbedPaneThe TAB control
      • The effect is simple and elegant, and the folding idea is adopted
  • This time I have completely improved the dialog layout

    • Previously, entire dialogs were written in length and width, which can be problematic at higher resolution screens
    • This time, I found the power of the Pack method, a complete refactoring of the interface layout logic
  • This time, on a 48-inch screen, that’s certainly not the case

I didn’t try, but I had confidence in my code

Mode selection

There are two big modes available: Default and Easy

Let’s see the difference

The default mode

  • view
class TestPage extends StatelessWidget {
  final logic = Get.put(TestLogic());
  final state = Get.find<TestLogic>().state;

  @override
  Widget build(BuildContext context) {
    returnContainer(); }}Copy the code
  • logic
class TestLogic extends GetxController {
  final TestState state = TestState();
}
Copy the code
  • state
class TestState {
  TestState() {
    ///Initialize variables}}Copy the code

Easy mode

  • view
class TestPage extends StatelessWidget { final logic = Get.put(TestLogic()); @override Widget build(BuildContext context) { return Container(); }}Copy the code
  • logic
class TestLogic extends GetxController {}Copy the code

conclusion

The above default mode and easy mode, from the code, or can see a very obvious difference

  • The Default mode has one more State layer than the Easy mode
  • State is specifically used to store page variables and initialize variable data

I once wrote a more complex module

  • The page has hundreds of variables (involving complex form submissions) and dozens of event interactions with the user
  • A lot of logic in the whole module depends on related variables to calibrate, and many different data will be initialized. The code of the State layer is almost a thousand lines faster
  • Therefore, as the business becomes increasingly complex, the State layer is not thin, which supports the logical calibration and torsion of the whole module

The Easy module is recommended unless it is a simple service module visible to the naked eye. In other cases, the Default mode is recommended

Main Functions (Main)

UseFolder, usePrefix

The useFolder and usePrefix functions are relatively simple and are described together here

useFolder

This function is selected by default. It creates a folder in addition to multiple files for easy management

usePrefix

Some people like to prefix each layer with the module name (lowercase + underscore) : view, state, logic.

There’s also an optional function for you to do that

isPageView

This is a very useful feature

If you use getX in PageView, you might notice that GetXController is injected into all of your child pages. Instead of switching to the corresponding page and injecting the corresponding GetXController!

PageView(children: [
    FunctionPage(),
    ExamplePage(),
    SettingPage(),
])
Copy the code

Analysis of the

We can analyze why this happens by looking at FunctionPage

class FunctionPage extends StatelessWidget {
  final logic = Get.put(TestLogic());
  final state = Get.find<TestLogic>().state;

  @override
  Widget build(BuildContext context) {
    returnContainer(); }}Copy the code

The steps we inject are placed in the scope of the class’s member variables

  • This scope takes effect before the constructor is instantiated
  • So when we add the Page to the instance, the scope of the member variable is triggered and GetXController is injected

PageView trigger mechanism

  • PageView triggers the build method of the Widget to be added
  • Switching to the Widget triggers the build method for that Widget

With this understanding, it’s easy to solve the PageView problem

  • Just put the injection process in the build method
  • Because we are using the StatelessWidget, we do not need to worry about its refresh; it is refreshed only when its parent is refreshed
  • The putIfAbsent method used by GetX to store objects avoids many problems by storing only the first injected object and ignoring subsequent objects of the same class

To deal with

So this function only needs to change the injection location of GetXController in the View file, not the other files

addBinding

Binding is for unified management of GetXController. Let’s look at the difference between binding and non-binding

The Binding

  • view
class TestOnePage extends StatelessWidget {
  final logic = Get.put(TestOneLogic());

  @override
  Widget build(BuildContext context) {
    returnContainer(); }}Copy the code
  • logic
class TestOneLogic extends GetxController {}Copy the code

Binding: A GetX route is required

  • binding
class TestTwoBinding extends Bindings {
  @override
  voiddependencies() { Get.lazyPut(() => TestTwoLogic()); }}Copy the code
  • view
class TestTwoPage extends StatelessWidget {
  final logic = Get.find<TestTwoLogic>();

  @override
  Widget build(BuildContext context) {
    returnContainer(); }}Copy the code
  • logic
class TestTwoLogic extends GetxController {}Copy the code
  • This binding is required under the routing module binding
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    returnGetMaterialApp( initialRoute: RouteConfig.testOne, getPages: RouteConfig.getPages, ); }}class RouteConfig {
  static const String testTwo = "/testTwo";

  static final List<GetPage> getPages = [
    GetPage(
      name: testTwo,
      page: () => TestTwoPage(),
      binding: TestTwoBinding(),
    ),
  ];
}
Copy the code

conclusion

In the Binding file, lazy injection is used: the actual injection occurs when the find method is used

So inside the view, you just have to change put to find, so to summarize

  • Add a Binding file using lazy injection
  • View file, put, find
  • You need to bind the Binding instance to the corresponding page of the getX routing module

Minor Functions

addLifecycle

This is a very simple function, just under the secondary TAB

Some logic modules need to write onReady and onClose callbacks frequently. So the plugin added the ability to automatically fill in both callbacks

  • Only Logic files are different

autoDispose

The feature is exactly what it’s called: automatically release GetXController

In fact, this is a very important feature, but it was implemented so inelegantly that it was moved to a secondary TAB

GetX does a lot of work internally to reclaim GetXController. The deallocation is handled in the GetX route. However, business variability and complexity make it difficult for some GetXControllers to be released automatically by the framework, for example:

  • Child page of PageView
  • Complex components encapsulated using GetX
  • Do not use GetX routing

None of these cases automatically reclaim GetXController; For this, I give a solution in the plugin, the difference is only in the View file

Universal solution

  • view
class TestTwoPage extends StatefulWidget {
  @override
  _TestTwoPageState createState() => _TestTwoPageState();
}

class _TestTwoPageState extends State<TestTwoPage> {
  final logic = Get.put(TestTwoLogic());

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

  @override
  void dispose() {
    Get.delete<TestTwoLogic>();
    super.dispose(); }}Copy the code
  • logic
class TestTwoLogic extends GetxController {

}
Copy the code

GetXController can be recovered by default (unless you manually enable GetXController).

But! You need to use the StatefulWidget! A lot more code! It’s so inelegant!

Optimized solution

The above is a general solution, you don’t need to introduce anything else; But this solution uses the StatefulWidget, which is a huge pile of code, and I’m a little confused

I have quite obsessive-compulsive disorder, think for a long time

  • GetBuilder is supposed to write a recycle logic and give a PR to the author

    • The getX framework already does this, but needs to be turned on with a parameter
    • The Obx refresh control cannot locate the GetXController inside the Obx refresh control, so it cannot do the recycle operation
  • That can only be done externally, so I wrote a generic control to recycle the corresponding GetXController

    • This generic control, which I also put PR on GetX, has been under review
    • Even if the control PR passes and is integrated into GetX, the lower version of GetX will not work
    • Here I present the generic recycle control code that you can copy into your project

GetBindWidget

  • The control can reclaim a single GetXController (bind parameter) and can add the corresponding tag (tag parameter); It is also possible to retrieve multiple GetXControllers (Cursories), which can be shared with multiple Tags (Tags correspond to Cursors-one; For GetXController without tag, the tag can be null: “”)
import 'package:flutter/material.dart';
import 'package:get/get.dart';

/// GetBindWidget can bind GetxController, and when the page is disposed,
/// it can automatically destroy the bound related GetXController
///
///
/// Sample:
///
/// class SampleController extends GetxController {
///   final String title = 'My Awesome View';
/// }
///
/// class SamplePage extends StatelessWidget {
///   final controller = SampleController();
///
///   @override
///   Widget build(BuildContext context) {
///     return GetBindWidget(
///       bind: controller,
///       child: Container(),
///     );
///   }
/// }
class GetBindWidget extends StatefulWidget {
  const GetBindWidget({
    Key? key,
    this.bind,
    this.tag,
    this.binds,
    this.tags,
    required this.child,
  })  : assert(
          binds == null || tags == null || binds.length == tags.length,
          'The binds and tags arrays length should be equal\n'
          'and the elements in the two arrays correspond one-to-one',),super(key: key);

  final GetxController? bind;
  final String? tag;

  final List<GetxController>? binds;
  final List<String>? tags;

  final Widget child;

  @override
  _GetBindWidgetState createState() => _GetBindWidgetState();
}

class _GetBindWidgetState extends State<GetBindWidget> {
  @override
  Widget build(BuildContext context) {
    return widget.child;
  }

  @override
  void dispose() {
    _closeGetXController();
    _closeGetXControllers();

    super.dispose();
  }

  ///Close GetxController bound to the current page
  void _closeGetXController() {
    if (widget.bind == null) {
      return;
    }

    var key = widget.bind.runtimeType.toString() + (widget.tag ?? ' ');
    GetInstance().delete(key: key);
  }

  ///Batch close GetxController bound to the current page
  void _closeGetXControllers() {
    if (widget.binds == null) {
      return;
    }

    for (var i = 0; i < widget.binds! .length; i++) {vartype = widget.binds! [i].runtimeType.toString();if (widget.tags == null) {
        GetInstance().delete(key: type);
      } else {
        varkey = type + (widget.tags? [i] ??' '); GetInstance().delete(key: key); }}}}Copy the code
  • It’s very simple to use
/// Reclaim a single GetXController
class TestPage extends StatelessWidget {
  final logic = Get.put(TestLogic());

  @override
  Widget build(BuildContext context) {
    returnGetBindWidget( bind: logic, child: Container(), ); }}/// Reclaim multiple GetXControllers
class TestPage extends StatelessWidget {
  final logicOne = Get.put(TestLogic(), tag: 'one');
  final logicTwo = Get.put(TestLogic());
  final logicThree = Get.put(TestLogic(), tag: 'three');

  @override
  Widget build(BuildContext context) {
    return GetBindWidget(
      binds: [logicOne, logicTwo, logicThree],
      tags: ['one'.' '.'three'], child: Container(), ); }}/// Recovery log
[GETX] Instance "TestLogic" has been created with tag "one"
[GETX] Instance "TestLogic" with tag "one" has been initialized
[GETX] Instance "TestLogic" has been created
[GETX] Instance "TestLogic" has been initialized
[GETX] Instance "TestLogic" has been created with tag "three"
[GETX] Instance "TestLogic" with tag "three" has been initialized
[GETX] "TestLogicone" onDelete() called
[GETX] "TestLogicone" deleted from memory
[GETX] "TestLogic" onDelete() called
[GETX] "TestLogic" deleted from memory
[GETX] "TestLogicthree" onDelete() called
[GETX] "TestLogicthree" deleted from memory
Copy the code

conclusion

For the above optimization scheme

  • Even if you don’t use GetX routing, you can easily reclaim the corresponding GetXController
  • This recycling method is common to both GetBuilder and Obx refresh mechanisms
  • Recycle time: Is when the current page is recycled

The only snafus: you’ll need to manually introduce the GetBindWidget into your project

LintNorm

This feature, at first glance, is probably confusing; If I hadn’t written it, I’d have read it

However, this function is the Gospel of a small number of obsessive-compulsive patients

Because the getX authors introduced the Lint library in the demo project, some of you may also use this library

Lint (pub) : pub. Dev /packages/li…

Lint is a code base with strict rules and will give hints via IDEA for code that is not standardized accordingly. For a lot of code that we think makes sense, we might sometimes give warnings as well

  • A few lines of generated template code will be warned under the Lint rule
    • Both of these injection codes automatically derive the corresponding type; However, under the Lint rule, there is a yellow underline warning

  • This adjustment is needed to remove the warning

Selecting the lintNorm button generates template code in the following form; So this feature is good news for people with OCD…

For people who use strong rules like Lint, I say:

Common suffix modification

  • Common name extensions can be changed

Wrap Widget

This is a very useful feature

Currently, four Wrap Widget types are supported: GetBuilder, GetBuilder (autoDispose), Obx, and GetX

Note: Click on the Widget and press Alt + Enter. Do not double-click to select the Widget name

  • GetBuilder

  • GetBuilder (Auto Dispose)
    • Set assignId to true: GetBuilder automatically reclaims its generic GetXController when the page is retracted

  • Obx
    • Why don’t you use the arrow symbol here, because if you want to wrap a Widget that’s really long, and you use the arrow symbol, the formatted code doesn’t look neat
    • For this reason, the return form is used

  • GetX
    • This component although I do not like to use, but there may be a friend like to use, added

  • Selective closing

Shortcut code generation

The plugin also provides you with the ability to type in keywords and generate snippets of code for fast keys

Note: The keyword prefix isgetx

Routing module

  • getxroutepagemap

  • getxroutename

  • getxroutepage

  • Getxto, getxtoname

  • Getxoff getXOffAll getXOffnamed getXOffAllNameed

Dependency injection

  • put

  • find

  • lazyPut

The business layer

  • GetxController

  • Getxfinal, getxfinal_

  • Getxget, getxget_

  • Getset, getset_

other

  • Getsnakebar, getDialog, getBottomSheet

  • Getxbuilder, getxobx

  • binding

There are other quick code, feel for yourself ~~

Version Update Description

X 3.1.

  • Significantly improve overall page layout
    • There will no longer be a pit ratio problem with tall screens
  • Support for lintNorm
  • Improved quick code prompt function, “get” prefix changed to “getx”
    • The getx prefix will drown the prompt code in a lot of system code, so it will be easy to see

X 3.0.

  • The project code was migrated from Java to Kotlin
  • ModuleName Enter: the initial letter is lowercase and the internal letter is automatically marked with uppercase
  • Add a lot of quick code snippet generation
  • Plug-in project logic reconstruction, interface layer and logical layer separation
  • Wrap Widget added: GetBuilder (Auto Dispose)
    • The corresponding GetXController can be automatically reclaimed
  • Add PageView solution
  • Fixed some bugs

X 2.1.

  • Major update!
  • Add Wrap Widget: GetBuilder, Obx, GetX
  • Add shortcut code snippet generation
  • Greatly optimize plug-in layout
  • Added complete lifecycle callback (addLifecycle)
  • AddBinding (addBinding)

X 1.5.

  • Added memory function (memory selection button)
  • Add GetXController autoDispose
  • You can modify common suffixes such as view, logic, and state
  • Adjust the plugin instructions and fix some bugs

X 1.3.

  • Adapted to multiple versions of IDEA (previously only adapted to one version of IDEA, pit)
  • Add the Logo of the plug-in
  • Add a getX English post (click on your blog post)
  • Improved plug-in description

1.2

  • Adjust description

1.1

  • Fixed packet guide exception when adding prefix

1.0

  • You can use this plugin to generate a lot of getX framework code
  • This can greatly increase your productivity
  • If you have any questions, please make an issue to me. Before mentioning: Please think about it first

The last

When I was constantly improving this plug-in, IT was also a process that I kept thinking,

Thank you for all your egg-aching needs

Can make this plugin a little bit better, so that now, can really help people save a little bit of development time

Series of articles + related address

  • The Github address of the plugin is getx_template

  • Use Flutter GetX — simple charm!

  • Flutter GetX depth profiling | we will out of my way (word graphic)