flutter第六篇:Get的基础使用

https://pub.dev/packages/get

中文文档:https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md

三大功能:

1、路由管理

跳转命名路由:Get.toNamed("/xxx")。如果要带参,则可在括号中用arguments参数指定。如Get.toNamed("/xxx", arguments: {"id": "20"})。

如果还是用GetMaterialApp的onGenerateRoute属性指定所有的路由,那么在目标页还是通过widget.params方式获取参数,其中params是目标页定义的全局变量。如果不想在目标页为了要获取参数而必须定义一个全局变量,则可以使用GetMaterialApp的routes属性或getPages属性,此时在目标页可以直接使用Get.arguments获取参数。利用getPages属性除了像routes一样可以指定所有的路由外,还可以实现很多其他的功能。getPages属性的值是一个GetPage数组。可以利用GetPage的middlewares属性设置很多中间件,如日志上报、登录校验(在跳转时,校验用户是否登录,如未登录就跳转到登录页面,否则正常跳转)。中间件类要继承GetMiddleware,重写其redirect方法,返回null则正常跳转,返回RouteSettings(name: "/login", arguments: {}),则跳转到login页面。还可以利用GetPage的transition属性设置跳转指定页面时的动画效果。如果要设置所有页面跳转的默认动画效果,可以利用GetMaterialApp的defaultTransition属性。

如果想让跳转的新页面不带返回按钮,那么需要用Get.offNamed("/xxx")跳转,这样在新页面就看不到顶部的返回按钮了,就不能点这个按钮跳回来了,适用于跳转登录页的情况。登录页面不能有返回按钮,登录完成后自动跳转其他页面。

返回到上一级页面:Get.back()。

返回到根:Get.offAllNamed("/")。

从A页面跳到B页面,再从B页面跳到C页面,如果想在C页面点回退按钮时直接退到A页面,则可以在B页面跳转C页面时,用offAndToNamed,即Get.offAndToNamed("C")。

2、状态管理

简单状态管理器GetBuilder

响应式状态管理器GetX

第一步:定义响应式变量

常规定义变量是var _counter  = 0,响应式变量定义是var _counter  = 0.obs,即在最后面加个.obs后缀,此时_counter的类型变为RxInt。

第二步:在触发式函数中改变响应式变量的值。所谓触发式函数,指的是经用户操作而触发的函数,如用户点击

_counter.value++;

_counter.value = 10;

第三步:在页面上用Obx包裹响应式变量,从而展示响应式变量的值

Obx(() => Text("${_counter.value}"))

如此,就可以在不调用setState的情况下实现状态局部刷新。setState多了,页面容易卡顿。

特殊的,在bottomSheet中,用Obx()不生效,必须要用GetBuilder,GetBuilder是StatefulWidget的子类。示例如下:

    Get.bottomSheet(GetBuilder<ProductContentController>(
      init: controller,
      builder: (controller) {
        return Container();
      },
    ));

如果想每次一进入页面就做些事情,则需要用GetBuilder的initState,指定一个函数。如购物车页面,每次一进入购物车页面就从服务端拉取最新的购物车商品列表数据。GetBuilder=Obx+initState。

在定义一个普通的实体类时,也可以设置其各属性为响应式属性,如

class Person {
  var username = "".obs;
  Person(this.username);
}
即把username的类型从String类型变成RxString类型。这样,在创建Person实例p后,就可以通过p.username.value = "xxx"给username赋值,通过Obx(() => Text("${p.username.value}"))展示。
特殊地,如果变量是RxList、RxSet、RxMap类型,访问其数据时,不需要用.value,直接当成List、Set、Map访问即可。

3、依赖管理

GetxController

如果不仅要实现状态局部刷新,还要实现状态页面间共享,那么就需要用GetxController。
第一步:自定义一个类,继承GetxController。在这个类中定义响应式变量,及修改其值的方法。注意,在方法中,修改完值后,要调用GetxController的update()方法。GetxController还有一个onInit()方法,可以用于进行一些初始化操作。
复制代码
import 'package:get/get.dart';

class CounterController extends GetxController {
  var counter = 0.obs;

  changeVaulue() {
    counter.value++;
    update();
  }

  dec() {
    counter.value--;
    update();
  }
}
复制代码

第二步:在HomePage中创建一个上述GetxController子类的实例,并调用Get的put()方法注入到内存中,即Get.put(CounterController()),这样在整个应用中的所有页面都可以使用这个实例了。在其他页面中可以通过Get的find()方法获取到这个实例,find()方法是支持泛型的,如用find<AController>()获取的是AController的实例,find<BController>()获取的是BController的实例。Get.put()方法有一个permanent参数,默认值是false,此时,假如我们在A页面中创建Controller实例并put,那么在退出A页面时,这个实例会被销毁,在B页面上是获取不到的。要想Controller实例全局可用,需要把permanent设为true。在HomePage中创建的话,permanent可以不设置为true,Controller实例不会销毁。

假设要在A、B、C页面展示和修改该属性值,则可以在各页面调用var counterController = Get.find<CounterController>()获取到CounterController实例,然后调用Obx(() => Text("${counterController.counter}"))展示属性值,调用counterController.changeValue()修改属性值。

创建GetxController子类实例并put,这个操作也可以在一个专门的类里处理,因为GetxController子类可能有很多,集中起来处理好管理。自定义一个类,实现Bindings接口。在重写dependencies方法时,创建GetxController各子类实例,并通过Get的lazyPut方法注入内存。

class AllControllerBinding implements Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => CounterController(), fenix: true);
  }
}

然后,在GetMaterialApp中,利用其initialBinding属性绑定这个Bindings实现类:initialBinding: AllControllerBinding()。最后在想用GetxController子类实例的地方,直接调用Get的find方法获取即可。

Get.lazyPut()方法是懒加载的,只有当用到了这个Controller实例时,这个Controller实例才会实例化并初始化。Get.lazyPut()方法有一个fenix参数,默认值是false,这表示只有我们第一次访问用到该Controller实例的页面时,该Controller实例才会实例化并初始化,之后我们再进的话,并不会重新实例化并初始化Controller实例。可是当我们退出该页面时,此Controller实例会被销毁,如此,下次在页面中就拿不到Controller实例了,就会有问题。

在第一次进页面时,会看到日志:

Instance "xxxController" has been created

Instance "xxxController" has been initialized

在退出页面时,会看到日志:

"xxxController" onDelete() called

"xxxController" deleted from memory

再次进入页面时,看不到create和initialize的日志,报错:"xxxController" not found. You need to call "Get.put(xxxController())" or "Get.lazyPut(()=>xxxController())"。

如果把fenix设置为true,则每次进页面都会初始化一个Controller实例,不会有拿不到Controller实例的情况。然而,每次进页面都创建一个新的Controller实例,会有属性丢失的问题。如我们在A页面通过调用Controller实例的方法设置了Controller的一个属性,退出A页面并重新进入,这时候因为Controller实例是新建的,所以之前设置的属性的值会丢失。

所以,在Bindings还是用Get.put()方法比较好,不会销毁,不用重建,只是xxxController实例会在还没访问到对应页面时就创建了。

如果A页面只使用了一种Controller,如CounterController,那么可以让A页面继承GetView<CounterController>,这样可以省去Get.find()的调用。GetView是StatelessWidget的子类,支持泛型。想访问CounterController实例的方法或属性,只需用controller即可,controller是GetView预定义的一个变量,值就是Get.find(),由于继承GetView时指定了类型,所以编辑器会自动分析出controller的类型,如CounterController类型。当然,不要忘了put或lazyPut CounterController实例。

如果报"xxxController" not found. You need to call "Get.put(xxxController())" or "Get.lazyPut(()=>xxxController())",那么可以

①不要lazyPut了,而是直接put。put()方法有个permanent参数,默认是false,表示是否持久化。为false或true都行。

或者

②让xxxView不再继承GetView<xxxController>,而是继承GetView,然后定义一个xxxController类型的实例controller,赋值为Get.put(xxxController()),之后在xxxView的build()方法中就可以通过这个controller实例调用在xxxController类中定义的实例方法了。

这两种方法都是真真正正的单例模式。

其他工具:

主题管理

Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());

国际化多语言管理

https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md#%E5%9B%BD%E9%99%85%E5%8C%96

要读取系统语言的话,需要把GetMaterialApp的locale属性赋值为View.of(context).platformDispatcher.locale。官方文档中使用的window,已经废弃了。

弹窗

Get.defaultDialog(),效果和showDialog+AlertDialog一样。通过title设置标题,通过middleText设置文案,通过confirm设置确认按钮及事件,通过cancel设置取消按钮及事件。和AlertDialog不一样的是,Get.defaultDialog的标题、文案、确认/取消按钮都会自动居中,且确认按钮在右边,取消按钮在左边。

Get.snackbar(),消息通知。效果和微信的新消息提醒一样,会滑出来一个带有标题和内容的框,默认从顶部滑下来,也可以设置成从底部滑上来。可以通过duration设置框的停留时间,默认为3s,到了这个时间后,框会原路返回。

Get.bottomSheet(),底部弹框。从屏幕底部中间位置往上弹出自定义的组件,组件底部与屏幕底部贴合。弹框会一直停留,不会自动消失。默认点击弹框外部,弹框会收回,可以通过isDismissible设置为不收回。可以通过enterBottomSheetDuration、exitBottomSheetDuration设置弹框弹出、收回的速度。

http请求

默认只能对https协议发起请求。

数据验证

GetUtils工具类有大量的工具方法可以使用,如判断是否是邮箱、判断是否是手机号,等等。

 

一些实用API:

Get.width,Get.height:获取屏幕的宽高。比较厉害,不需要context,这样在initState()方法中也可以获取到宽高了。

Get.previousRoute:看是从哪个页面跳过来的。

Get.isDialogOpen,Get.isSnackbarOpen,Get.isBottomSheetOpen,Get.isOverlaysOpen:查看是否有弹框。

Get.context:获取当前的上下文。

Get.context?.isPortrait,Get.context?.isLandscape:判断当前是竖屏还是横屏。

Get.context还有很多属性可以获取,直接打点即可。

 

get_cli,get的脚手架,提供了很多命令,可以生成一些包结构,主打一个结构清晰,视图(view)和控制器(controller)分离。需要执行pub global activate get_cli命令安装,安装完之后要配置环境变量。

先用编辑器New Flutter Project,然后执行get init初始化,之后在对应的目录开发即可。如新建主页模块,get create page:home,详见https://github.com/jonataslaw/get_cli/blob/master/README-zh_CN.md

get init时,自己要手动输两次1。

 

踩过的一个大坑:

run时,报

type 'HomeController' is not a subtype of type 'HomeController' in type cast where
  HomeController is from package:xmshop/app/modules/home//controllers/home_controller.dart
  HomeController is from package:xmshop/app/modules/home/controllers/home_controller.dart

在网上搜不到任何相关的信息。最终发现,是在binding类中,import home_controller.dart文件时,路径写错了,本来应该是'../../home/controllers/home_controller.dart',写成了'../../home//controllers/home_controller.dart',即多了个斜杠。编译时ide没有报错,但是运行失败。

posted on 2024-10-21 14:40  koushr  阅读(344)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示