GetX代码生成IDEA插件,超详细功能讲解(透过现象看本质)

23,860 阅读17分钟

前言

本文章不是写getx框架的使用,而且其代码生成IDEA插件的功能讲解

我之前写过俩篇很长很长的getx文章

一篇入门使用:Flutter GetX使用---简洁的魅力!

一篇原理深度剖析:Flutter GetX深度剖析 | 我们终将走出自己的路(万字图文)

鱼和渔都已经交给大家了,就没必要去赘述了

img

同时,我也写了一个getx代码生成插件:getx_template,这个工具相当于钓鱼座椅(让你更舒服的钓鱼或吃鱼?)吧!初期功能十分简单,就是生成单页面相应的模块代码,连个记忆选项功能都没有,基本上就是个塑料座椅的程度

  • 但是随着大量 叼毛 靓仔 给我提的各种需求,这个插件变的已经有点复杂了
  • 尤其是涉及Select Function模块,有些人可能都搞不懂选中的功能按钮是啥意思,就一通全部勾中。。。
  • 所以,本凤雏想详细的,和各位卧龙谈谈这个工具方方面面的功能,希望能帮助各位节省点开发时间

兄弟们,我实在不想写水文;但是这个工具一个功能按钮,改变的代码可能很少,其背后所蕴含的东西,可能需要大量的笔墨去描述,这边就统一的和各位彦祖于宴亦菲们,说道说道。

img

本文长期更新,如果想知道插件每次详细更新内容,可以点进来看。

代码生成

  • Plugins里搜索getx即可

image-20210906222922384

对比

  • 早期代码生成弹框,可选功能比较少,当时还不支持持久化储存
    • 淦,图标也丑

20210130182809

  • 这是多次完善后的功能选择弹窗

getx_new

鄙人是个十足的颜值党,这次最新版本的页面,我做了很多考量

  • 首页随着各位靓仔提的各种需求,Select Function,从最初的俩个功能,增加到现在的七个功能

    • 随着功能按钮的增多,在dialog上平铺下来,整个dialog的高度会变得相当的长
    • 最重要的是:会让使用者,不明确Function里面的重点功能按钮是什么!
  • 基于上述的思考,我绞尽脑汁的想解决这个问题

    • 方案一:我本来是想做一个折叠收纳区域,次要功能按钮放在折叠区域中
      • 用swing一通写后,发现效果是真的丑,收纳的时候,高度计算也有问题:放弃
    • 方案二:这个是我在翻swing控件的时候,发现了 JBTabbedPane 这个tab控件
      • 效果简洁优雅,完爆折叠思路:采用
  • 这次我全面的改善了dialog布局问题

    • 以前的整个dialog的长宽是写死的,在高尺寸的分辨率屏幕上会存在问题
    • 这次,发现了pack方法的妙用(swing菜狗的辛酸泪),全面重构的界面布局逻辑
  • 这一次,在48寸的屏幕上,肯定不会出现下面这种情况了

圖片

虽然我没试,但是我对自己的代码有信心

img

模式选择

这里提供俩种大的模式选择:default,easy

来看下区别

default模式

image-20210905174923566

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

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

Easy模式

image-20210905175435395

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

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
  • logic
class TestLogic extends GetxController {

}

总结

上面的default模式和easy模式,从代码上看,还是能看出很明显的区别

  • Default模式比Easy模式多了一个State层
  • State是专门用来存放页面变量和初始化相关变量数据的

我曾写过一个比较复杂模块

  • 页面的变量达到几百个(涉及到复杂的表单提交),与用户的事件交互也有几十个
  • 整个模块很多逻辑依靠相关变量去标定,会初始化很多不同数据,State层的代码几乎快一千行
  • 所以当业务逐渐的复杂,State层并不薄,他支撑着整个模块的逻辑标定和扭转

除非是肉眼可见的业务极简模块,推荐使用Easy模块;其余的情况推荐使用Default模式

main(主要功能)

useFolder,usePrefix

useFolder和usePrefix功能比较简单,这里就放在一起讲了

useFolder

本项功能是默认选中的,会在创建的多个文件外,创建一个文件夹,方便管理

useFolder

usePrefix

一些小伙伴喜欢在各层:view,state,logic,前加上module名的前缀(小写+下划线)

这边也为大家提供了一个这样的可选功能

usePrefix

isPageView

请注意:isPageView和autoDispose按钮不能同时选中,他们俩都能解决PageView中存的问题,选择其中一按钮,另一按钮会自动取消勾选

这算是一个非常有用的功能了

如果大家在PageView中使用getx,可能会发现,所有的子页面中的GetXController,一下全被注入了!并不是切换到对应页面,注入对应的GetXController!

PageView(children: [
    FunctionPage(),
    ExamplePage(),
    SettingPage(),
])

分析

我们可以来分析下,为什么会发生这种情况,来看下:FunctionPage

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

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

我们注入的步骤,是放在类的成员变量作用域

  • 这个作用域是在实例化构造函数之前起效的
  • 所以我们在添加被实例的Page的时候,成员变量的作用域直接被触发,GetXController就被注入

PageView触发机制

  • PageView触发被添加Widget,是触发对应Widget的build方法
  • 切换到哪个Widget,就触发对应Widget的build方法

有了上面这层理解,就很容易解决PageView的问题了

  • 只需要将注入过程放在build方法中
  • 因为我们使用的是StatelessWidget,并不需要考虑其刷新问题,只有它的父节点刷新,它才会被刷新
  • GetX存储对象使用的putIfAbsent方法,只会存储第一次注入对象,后续相同类的对象直接忽略,这能避免很多问题

处理

所以此功能只需要改变View文件里,GetXController的注入位置即可(其它文件不需要改动)

class FunctionPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final logic = Get.put(FunctionLogic());
    final state = Get.find<FunctionLogic>().state;

    return Container();
  }
}
  • 对比

isPageView

addBinding

binding是为了统一管理GetXController,来看下binding和非binding的区别

addBinding

非Binding

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

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
  • logic
class TestOneLogic extends GetxController {

}

Binding:需要配套GetX路由

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

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
  • logic
class TestTwoLogic extends GetxController {

}
  • 需要在路由模块绑定下这个binding
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      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(),
    ),
  ];
}

总结

binding文件里面,使用的是懒注入:在使用了find方法的时候,才会真正的注入

所以在view里面,就需要将put改成find就行了,总结下

  • 增加binding文件,使用懒注入
  • view文件,put改成find
  • 需要在getx路由模块,对应的页面上绑定binding实例

minor(次要功能)

addLifecycle

这是个非常简单的功能,就放在次要功能tab下

一些小伙伴,logic模块需要经常写onReady和onClose回调,懒得每次手写;所以在插件里添加了自动补上这俩个回调的功能

  • 仅仅Logic文件有区别,开启该功能时:会自动添加onReady()和onClose()方法
class TestLogic extends GetxController {
  final TestState state = TestState();

  @override
  void onReady() {
    // TODO: implement onReady
    super.onReady();
  }

  @override
  void onClose() {
    // TODO: implement onClose
    super.onClose();
  }
}
  • 对比

addLifecycle

autoDispose

该功能正如名字一样:自动释放GetXController;实际上,这是个非常重要的功能,但是实现的太不优雅了,就把它移到了次要功能tab里面了

在我们使用GetX的时候,可能没什么GetxController未被释放的感觉,这种情况,是因为我们一般都是用了getx的那一套路由跳转api(Get.to、Get.toName...)之类:使用Get.toName,肯定需要使用GetPage;如果使用Get.to,是不需要在GetPage中注册的,Get.to的内部有一个添加到GetPageRoute的操作

通过上面会在GetPage注册可知,说明在我们跳转页面的时候,GetX会拿你到页面信息存储起来,加以管理,下面俩种场景会导致GetxController无法释放

  • GetxController可被自动释放的条件

    • GetPage+Get.toName配套使用,可释放
    • 直接使用Get.to,可释放
  • GetxController无法被自动释放场景

    • 未使用GetX提供的路由跳转:直接使用原生路由api的跳转操作
    • 这样会直接导致GetX无法感知对应页面GetxController的生命周期,会导致其无法释放
Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => XxxxPage()),
);

由此,可从上面可以看出,GetxController无法被释放的场景:不使用GetX路由

最优解

有个最优解方案,就算你不使用Getx路由,也能很轻松回收各个页面的GetXController,感谢 @法的空间 在评论里指出

  • 手动让getx感知路由
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage,
      ///此处配置下!
      navigatorObservers: [GetXRouterObserver()],
    );
  }
}

///自定义这个关键类!!!!!!
class GetXRouterObserver extends NavigatorObserver {
  @override
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    RouterReportManager.reportCurrentRoute(route);
  }

  @override
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) async {
    RouterReportManager.reportRouteDispose(route);
  }
}

讲真的,这个原理其实很简单,但是思路很有趣;大家点进reportCurrentRoutereportRouteDispose 这俩个方法,大概就知道是怎么回事了

  • reportCurrentRoute 就是让当前的路由标定给GetX
  • 当我们进入一个页面的时候,相应GetXController会进行初始化,最终会调用 _startController<S>({String? tag})方法
  • _startController中会调用RouterReportManager.appendRouteByCreate(i),将注入的GetXController都保存起来
  • 保存在一个map中,key为当前路由route,value为HashSet,可以保存多个GetXController
  • ok,路由关闭的时候,在reportRouteDispose方法中回收,key为当前route,遍历value中所有的GetXController回收
  • 我giao,基于这种思路,大家能干很多事了!!!

StatefulWidget方案

如果上面的最优解没法帮你解决GetXController的回收问题,你可能就遇到特殊的场景了,一般来说,分析分析你自己的代码,基本都能分析出来

如果懒得分析原因,就试试下面这种折中方案吧;颗粒度极小,针对单页面维度解决

这边我模拟了上面场景,写了一个解决方案

  • 第一个页面跳转
Navigator.push(
    Get.context,
    MaterialPageRoute(builder: (context) => AutoDisposePage()),
);
  • 演示页面
    • 这地方地方必须要使用StatefulWidget,因为在这种情况,无法感知生命周期,就需要使用StatefulWidget生命周期
    • 在dispose回调处,把当前GetxController从整个GetxController管理链中删除即可
class AutoDisposePage extends StatefulWidget {
  @override
  _AutoDisposePageState createState() => _AutoDisposePageState();
}

class _AutoDisposePageState extends State<AutoDisposePage> {
  final AutoDisposeLogic logic = Get.put(AutoDisposeLogic());

  @override
  Widget build(BuildContext context) {
    return BaseScaffold(
      appBar: AppBar(title: const Text('计数器-自动释放')),
      body: Center(
        child: Obx(
          () => Text('点击了 ${logic.count.value} 次',
              style: TextStyle(fontSize: 30.0)),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => logic.increase(),
        child: const Icon(Icons.add),
      ),
    );
  }

  @override
  void dispose() {
    Get.delete<AutoDisposeLogic>();
    super.dispose();
  }
}

class AutoDisposeLogic extends GetxController {
  var count = 0.obs;

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

看到这,你可能会想,啊这!怎么这么麻烦,我怎么还要写StatefulWidget,好麻烦!

各位放心,这个问题,我也想到了,我特地在插件里面加上了自动回收的功能

  • 如果你写的页面无法被回收,记得勾选autoDispose
    • 怎么判断页面的GetxController是否能被回收呢?实际上很简单,上面的未被释放的场景已经描述的比较清楚了,不清楚的话,就再看看

image-20210922112126153

来看下代码,default模式一样可以的

  • view
class AutoDisposePage extends StatefulWidget {
  @override
  _AutoDisposePageState createState() => _AutoDisposePageState();
}

class _AutoDisposePageState extends State<AutoDisposePage> {
  final AutoDisposeLogic logic = Get.put(AutoDisposeLogic());

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

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

}

优化StatefulWidget方案

上面的是个通用解决方法,你不需要额外的引入任何其它的东西;但是这种方案用到了StatefulWidget,代码多了一大坨,让我有点膈应

鄙人有着相当的强迫症,想了很久,从外部入手,我就写了一个通用控件,来对相应的GetXController进行回收

GetBindWidget

  • 本控件含义:将GetXController和当前页面的生命周期绑定,页面关闭时,自动回收

  • 该控件可以回收单个GetXController(bind参数),可以加上对应tag(tag参数);也可以回收多个GetXController(binds),可以加上多个tag(tags参数,请和binds 一 一 对应;无tag的GetXController的,tag可以写成空字符:"")

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 = Get.put(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++) {
      var type = widget.binds![i].runtimeType.toString();

      if (widget.tags == null) {
        GetInstance().delete(key: type);
      } else {
        var key = type + (widget.tags?[i] ?? '');
        GetInstance().delete(key: key);
      }
    }
  }
}
  • 使用非常的简单
/// 回收单个GetXController
class TestPage extends StatelessWidget {
  final logic = Get.put(TestLogic());

  @override
  Widget build(BuildContext context) {
    return GetBindWidget(
      bind: logic,
      child: Container(),
    );
  }
}

/// 回收多个GetXController
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(),
    );
  }
}

/// 回收日志
[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

LintNorm

pub:lint库

这个功能,乍一看,大家估计都懵逼了;这要不是我写的,我看了也懵逼啊

img

但是,这个功能,真是少部分强迫症患者的福音

因为getx作者,在demo项目里面,引入的lint库,一些小伙伴可能也用了这个库

lint是一个严格规则的代码库,对于代码相应不规范的地方,会通过IDEA给与提示;对于我们很多认为合理的代码,有时候可能也会给出相应的警告

  • 在生成的模板代码,有几行就会在lint规则下被警告
    • 这俩个注入代码,都会自动推导出对应的类型;但是在lint规则下,会有黄色下划线警告

image-20210906174811659

  • 需要做这样的调整,才能去掉警告

image-20210919172158224

选中lintNorm按钮,就会以下面这种形式生成模板代码;所以说这个功能是强迫症患者福音。。。

对于用lint这种强规则的人,我表示:

img

pub:flutter_lints

最近Flutter在新建项目里面,默认加上了flutter_lints这个库,这个库的规则宽松很多,规则基本也是规范flutter的写法

  • 生成了模板代码里面,会有一个警告

image-20210918222832370

  • 需要做如下调整,才能去掉警告

image-20210918222957089

当你开启lintNorm,也会帮你补上生成页面的构造函数

template(切换模板命名)

场景

该功能提供了切换模板命名的操作

提供三套模板命名,只提供三套,不会再多增了

内部对持久化模块进行了重构

  • 不重构不行,增加了大量的持久化变量,还全部使用静态变量着实不优雅
  • 增加了数据类,来记录大量重复的持久化数据

为什么要提供切换模板命名的功能?

当业务逐渐的复杂,很多时候,复杂的通用组件,也可以使用getx去封装

  • 但是使用插件生成对应模块,view模块的Widget可能还是为XxxPage
  • 上面这种情况就不太友好了,你可能需要XxxComponent或者XxxWidget
  • 虽然,可以在设置里重命名后缀名,但是这样可能又对生成Page模块产生影响
  • 所以,这里提供三套模板命名切换,可以快速切换到你需要的自定命名方式

功能演示

插件窗口增加三套模板切换

  • 选择Template,提供三套切换模板命名:Page、Component、Custom
    • 默认Page

image-20210914222313651

三套模板命名都支持自定义修改

  • 上面的切换,对应设置页面的三套自定义通用后缀
    • 设置页面布局也重写了,看起来更舒服一些,对整体空间利用率也更高了

image-20210919122822352

示例

  • mode选择:Easy;Template选择:Component

image-20210914223626196

看下代码

  • view
class TestComponent extends StatelessWidget {
  final logic = Get.put(TestLogic());

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
  • logic
class TestLogic extends GetxController {

}

Wrap Widget

这是一个非常好用的功能

目前支持四种Wrap Widget类型:GetBuilder,GetBuilder(autoDispose),Obx,GetX

使用注意事项:鼠标点击在Widget上即可,然后按 alt+enter;请勿双击选中Widget名字

  • GetBuilder

GetBuilder

  • GetBuilder(Auto Dispose)
    • assignId设置为true:GetBuilder就会在页面被回收的时候,自动回收其指定泛型的GetXController

GetBuilder(Auto Dispose)

  • Obx
    • 说下这里为什么不用箭头符号,如果需要包裹的Widget非常长的话,使用箭头符号后,格式化后的代码并不整齐
    • 考虑到这种情况,所以使用了return形式

Obx

  • GetX
    • 这个组件我虽然不太喜欢用,但是指不定有喜欢用的小伙伴,就加上了

GetX

  • 可选择性关闭

image-20210802160631405

快捷代码生成

插件也为大家提供了,输入关键字生成快键代码片段的功能

请注意:关键字前缀为getx

路由模块

  • getxroutepagemap

getxroutepagemap

  • getxroutename

getxroutename

  • getxroutepage

getxroutenpage

  • getxto,getxtoname

getxto

  • getxoff,getxoffall,getxoffnamed,getxoffallnameed

getxoff

依赖注入

  • put

getxput

  • find

getxfind

  • lazyPut

getxlazyput

业务层

  • GetxController

getxcontroller

  • getxfinal,getxfinal_

getxfinal

  • getxget,getxget_

getxget

  • getset,getset_

getset

其它

  • getsnakebar,getdialog,getbottomsheet

getxdialog

  • getxbuilder,getxobx

getxobx

  • binding

getxbinding

还有其它的一些快捷代码,自行感受喽~~

Setting功能

随着功能的不断增加,一些细分功能,需要在放在设置模块里了,是时候写下详细说明了。

lintNorm细分

  • 开启 lintNorm 功能时,生成的模板代码是支持俩种库的:lint 和 flutter_lints

image-20211207102535779

  • 现在对支持做了细分,大家可以随意设置:支持其中一种库或者都支持

image-20210926112241600

useFolderSuffix

这个功能可以选择是否使用文件夹后缀,默认关闭

useFolderSuffix未选中的时候

  • 设置页面

image-20211207093055755

  • 生成的文件夹是这样的

image-20211207102221083

useFolderSuffix选中的时候

  • 设置页面

image-20211207101105948

  • 文件夹后追加后缀

image-20211207101246498

  • 追加的后缀,是各Template中ViewName字段

image-20211207101459335

版本更新说明

3.3.x

  • 调整StatefulWidget模板
  • 优化wrap功能
  • lintNorm默认值修改为true

3.2.x

  • 增加模板切换功能,大幅度优化内部持久化方式
  • 重构设置页面布局
  • 支持 flutter_lints 规则
  • 拆分lintNorm:lint 和 flutter_lints (可在设置里自定义支持)
  • 修复Template标题丢失(感谢 @胶带 帮忙测试)
  • 设置里增加useFolderSuffix功能

3.1.x

  • 显著的提升整体页面布局
    • 高尺寸屏幕不会再出现坑比问题了
  • 支持lint规则(lintNorm)
  • 改善快捷代码提示功能,“get”前缀改成为“getx”
    • get为前缀,会让提示代码被很多系统代码淹没,改为getx之后就可以一目了然了
  • 插件描述页面,添加本篇文章链接

3.0.x

  • 项目代码从Java迁移为kotlin
  • ModuleName输入:首字母小写,内部会自动标为大写
  • 增加大量快捷代码片段生成
  • 插件项目逻辑重构,界面层和逻辑层分离
  • Wrap Widget增加:GetBuilder(Auto Dispose)
    • 可自动回收对应的GetXController
  • 增加PageView解决方案
  • 修复一些bug

2.1.x

  • 重大更新!
  • 增加Wrap Widget:GetBuilder,Obx,GetX
  • 增加快捷代码片段生成
  • 大幅度优化插件布局
  • 增加完善生命周期回调功能(addLifecycle)
  • 添加binding功能(addBinding)

1.5.x

  • 增加记忆功能(记忆选择的按钮)
  • 添加GetXController自动回收功能(autoDispose)
  • 支持修改通用后缀:view,logic,state
  • 调整插件说明,修复一些bug

1.3.x

  • 适配多版本的IDEA(之前只适配了一个IDEA版本,坑)
  • 添加插件logo
  • 增加一篇getx英文文章(机翻自己的博客文章)
  • 改善插件描述

1.2

  • 调整描述内容

1.1

  • 修复增加前缀时,发生的导包异常问题

1.0

  • 你可以使用本插件生成大量的getx框架代码
  • 这能大大提升你的效率
  • 如果有任何问题,欢迎给我提issue;提之前:请先思考下,合不合理

最后

在不断完善这个插件的时候,也是我不断思考的一个过程,

感谢大家提的各种蛋痛的需求

img

能让这个插件一点点的完善,以至于现在,,能真正的帮助靓仔们节省一点开发时间

img

系列文章 + 相关地址