Notas Flutter | GetX

Sitio web oficial: https://pub.dev/packages/get
Documentación en chino: https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md

Acerca de GetX

Ahora hay muchas soluciones de administración de estado para Flutter, como redux, block, state, provider y Getx.

Provider es una solución de gestión estatal oficial, y su función principal es la gestión estatal. Getx es un complemento de gestión de estado de terceros. No solo tiene la función de gestión de estado, sino que también tiene funciones como gestión de enrutamiento, gestión de temas, gestión multilingüe internacional, actualización parcial de Obx, solicitud de red, verificación de datos, etc. En comparación con otros complementos de administración de estado, Getx es más simple, potente y de alto rendimiento.

En pocas palabras, la mayor ventaja de GetX sobre la solución original y otras es que es fácil de usar, rica en funciones y proporciona una API funcional de estilo familiar de pies a cabeza.

  • GetX es una solución liviana y poderosa en Flutter: administración de estado de alto rendimiento, inyección de dependencia inteligente y administración de enrutamiento conveniente.

  • GetX tiene 3 principios básicos:

    • Rendimiento: GetX se centra en el rendimiento y el consumo mínimo de recursos. El tamaño del apk empaquetado y el uso de la memoria en tiempo de ejecución de GetX son comparables a otros complementos de administración de estado.
    • Eficiencia: la sintaxis de GetX es muy simple y mantiene un rendimiento extremadamente alto, lo que puede reducir considerablemente el tiempo de desarrollo.
    • Estructura: GetX puede desacoplar por completo la interfaz, la lógica, las dependencias y el enrutamiento, lo que lo hace más limpio de usar, más claro en la lógica y más fácil de mantener en el código.
  • GetX no está inflado, pero es muy liviano. Si solo usa la administración de estado, solo se compilará el módulo de administración de estado, y otras cosas que no se usen no se compilarán en su código. Tiene numerosas funciones, pero estas funciones están en contenedores separados, que no se inician hasta que se usan.

  • Getx tiene un gran ecosistema y puede ejecutar el mismo código en Android, iOS, Web, Mac, Linux, Windows y su servidor.
    A través de Get Server , puede reutilizar completamente el código que escribió en el front-end en su back-end.

GetX tiene principalmente tres funciones principales:

  • administración del Estado
  • gestión de enrutamiento
  • gestión de dependencia

Introducir respectivamente a continuación.

Instalar

Agrega Get a tu archivo pubspec.yaml.

dependencies:
  get: ^4.6.5

Importarlo en el archivo requerido y se utilizará.

import 'package:get/get.dart';

Establecer entrada de aplicación

Cuando importamos dependencias, el primer paso es reemplazar el main.dartoriginal en el archivo de entrada como el nivel superior, como se muestra a continuación.MaterialAppGetMaterialApp

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
    
    
	runApp(GetXApp ());
}

class GetXApp extends StatelessWidget {
    
    
  const GetXApp({
    
    super.key});
  
  Widget build(BuildContext context) {
    
    
    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
          primarySwatch: Colors.blue,
          appBarTheme: const AppBarTheme(centerTitle: true,)
      ),
      home: const GetXHomePage(),
    );
  }
}

Gestión de estado de respuesta GetX

Por ejemplo, usar GetX para modificar la aplicación de muestra de contador predeterminada de Flutter requiere solo tres pasos:

Paso 1: al definir una variable, agregue .obsel sufijo al final de la variable

var _counter = 0.obs;

Paso 2: Donde se usan variables, utilícelas Obxpara envolver

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

Paso 3: cuando se haga clic en el botón, modifique el valor de la variable directamente y la interfaz de usuario se actualizará automáticamente

 onPressed: () => _counter++

Eso es todo, es tan simple como eso. Ni siquiera setStatenecesita ser llamado.

Hay tres formas de declarar una variable reactiva:

El primero usa Rx{Tipo}

final name = RxString('');
final isLogged = RxBool(false);
final count = RxInt(0);
final balance = RxDouble(0.0);
final items = RxList<String>([]);
final myMap = RxMap<String, int>({
    
    });

El segundo es usar Rx, especificando un Rx genérico .

final name = Rx<String>('');
final isLogged = Rx<Bool>(false);
final count = Rx<Int>(0);
final balance = Rx<Double>(0.0);
final number = Rx<Num>(0)
final items = Rx<List<String>>([]);
final myMap = Rx<Map<String, int>>({
    
    });
final user = Rx<User>(); // 自定义类 - 可以是任何类

La tercera forma, más práctica, más simple y preferible, es simplemente agregar .obsel atributo como valor. ( recomendado )

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;  // 自定义类 - 可以是任何类

Para otro ejemplo, definamos un List:

 RxList _list = ["张三", "李四"].obs;

y luego usarlo:

Obx(() {
    
    
  return Column (
    children: _list.map((v) {
    
     return ListTile(title: Text(v));}).toList(),
  );
}),

Modifíquelo después:

 onPressed: () => _list.add("王五");

Nota: Obxexiste una correspondencia uno a uno con las variables de estado correspondientes. Si hay varias variables, no puede simplemente envolver una en la capa más externa Obx. Cada lugar que usa variables Rx debe envolverse Obx.

Escuche los cambios en los datos de la clase personalizada

1. Cree una clase de persona y modifique las variables miembro de manera receptiva

import 'package:get/get.dart';

class Person {
    
     
	RxString name = "Jimi".obs; // rx 变量
	RxInt age = 18.obs;
}

2. Obtenga el valor del atributo de clase y cambie el valor

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import './person.dart';
void main() {
    
    
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
    
    
  const MyApp({
    
    super.key}); 
  
  Widget build(BuildContext context) {
    
    
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
    
    
  const MyHomePage({
    
    super.key});
  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
    
    
  var person = Person(); // 定义 Person 对象
  
  
  Widget build(BuildContext context) {
    
    
    return Scaffold(
      appBar: AppBar(
        title: const Text("Getx Obx"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Obx(() => Text(   // 读取时使用Obx包裹
                  "我的名字是 ${
      
      person.name}",
                  style: const TextStyle(color: Colors.red, fontSize: 30),
                ))
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
    
    
          person.name.value = person.name.value.toUpperCase(); // 修改值
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

De otra manera, también puede definir toda la clase como receptiva, por ejemplo:

import 'package:get/get.dart';

class Animal {
    
    
  String username;
  int age;
  Animal(this.username,this.age);
}

Al crear el Animalobjeto anterior, puede agregar directamente .obsel sufijo:

var a = Animal("xiao mao", 2).obs;

Todavía uso Obxel embalaje

Obx(() => Text(a.username))

Al modificar, debe modificar la orientación del puntero variable:

onPressed: () => a.value = Animal("小狗", 3)

Gestión de enrutamiento GetX

Si solo necesita configurar la página de Inicio, es MaterialApplo mismo que:

GetMaterialApp( // Before: MaterialApp(
  home: MyHome(),
)

Si necesita configurar la tabla de enrutamiento:

GetMaterialApp(
  debugShowCheckedModeBanner: false,
  title: 'Flutter Demo',
  theme: ThemeData(
      primarySwatch: Colors.blue,
      appBarTheme: const AppBarTheme(centerTitle: true)
   ), 
  initialRoute: "/", 
  defaultTransition: Transition.rightToLeft, // 配置全局路由页面切换动画效果
  getPages: AppPage.routes, // 配置路由表
);
// routes.dart
// 路由表, 可放在单独文件中
import 'package:get/get.dart';

class AppPage {
    
    
  static final routes = [
    GetPage(name: "/", page: () => const Tabs()),
    GetPage(name: "/shop", page: () => const ShopPage(), middlewares: [ShopMiddleWare()]),
    GetPage(name: "/login", page: () => const LoginPage()),
    GetPage(name: "/registerFirst", page: () => const RegisterFirstPage(), transition: Transition.fade),// 单独指定某个路由页面切换效果
    GetPage(name: "/registerSecond", page: () => const RegisterSecondPage()),
    GetPage(name: "/registerThird", page: () => const RegisterThirdPage()),
  ];
}

Método de salto de ruta común GetX:

método Función
Get.to() saltar a la nueva página
Get.toNamed() Salto de enrutamiento con nombre
Get.back() ruta de regreso
Get.off() Va a la página siguiente, pero no tiene la opción de volver a la página anterior (para páginas de pantalla de bienvenida, páginas de inicio de sesión, etc.)
Get.offAll() Ir a la página siguiente y cancelar todas las rutas anteriores
Get.offAndToNamed() Saltar y reemplazar la página de ruta actual con la siguiente ruta (se puede usar para cerrar páginas intermedias, como páginas de búsqueda)
Get.removeRoute() eliminar una ruta
Get.until() devuelve repetidamente hasta que la expresión devuelve verdadero
Get.offUntil() Vaya a la siguiente ruta y elimine todas las rutas anteriores hasta que la expresión devuelva verdadero
Get.offNamedUntil() Va a la siguiente ruta nombrada y elimina todas las rutas anteriores hasta que la expresión devuelve verdadero
Get.arguments Obtener los parámetros de la página de enrutamiento actual
Get.previousRoute Obtener el nombre de la ruta anterior
Get.rawRoute Dar la ruta original para visitar

Valor del pase de ruta:

Get.toNamed("/shop", arguments: {
    
    "id":3456});

Recibir página:

print(Get.arguments);

Enrutamiento de páginas intermedias:

GetPageLos parámetros en la configuración de la tabla de enrutamiento anterior middlewarespueden configurar la página intermedia del salto de enrutamiento, y algunos servicios como el juicio de permiso y la intercepción se pueden realizar en esta página, por ejemplo:

// shopMiddleware.dart
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';

class ShopMiddleWare extends GetMiddleware {
    
    
  
  RouteSettings? redirect(String? route) {
    
    
    print("跳转ShopPage路由页面的中间页面-------");
    // return null;  // 返回空表示不做任何操作,走原来的路由跳转逻辑,即跳转到ShopPage
    // 此处可判断没有权限后跳转到登录页面
    return const RouteSettings(name: "/login", arguments: {
    
    });
  }
}

prioridad

Establecer la prioridad del middleware define el orden de ejecución de Get middleware.

final middlewares = [
  GetMiddleware(priority: 2),
  GetMiddleware(priority: 5),
  GetMiddleware(priority: 4),
  GetMiddleware(priority: -8),
];

Este middleware se ejecutará en este orden : 8 => 2 => 4 => 5

Aquí hay GetMiddlewarealgunos otros métodos de:

  • onPageCalled: esta función se llamará cuando se llame a la página, antes de que se cree nada. Puede usar esto para cambiar algo sobre la página o darle una nueva página.
GetPage onPageCalled(GetPage page) {
    
    
  final authService = Get.find<AuthService>();
  return page.copyWith(title: 'Welcome ${
      
      authService.UserName}');
}
  • **OnBindingsStart:** Esta función se llamará antes de que se inicialicen los enlaces. Aquí puede cambiar los enlaces de esta página.
List<Bindings> onBindingsStart(List<Bindings> bindings) {
    
    
  final authService = Get.find<AuthService>();
  if (authService.isAdmin) {
    
    
    bindings.add(AdminBinding());
  }
  return bindings;
}
  • OnPageBuildStart: esta función se llamará después de la inicialización del enlace. Aquí puede realizar algunas operaciones después de crear enlaces y antes de crear widgets de página.
GetPageBuilder onPageBuildStart(GetPageBuilder page) {
    
    
  print('bindings are ready');
  return page;
}
  • OnPageBuilt: se llamará a esta función después de llamar a GetPage.page, y dará el resultado de la función, y hará que se muestre el widget.

  • OnPageDispose: esta función se llamará después de eliminar todos los objetos relacionados de la página (Controladores, vistas, …).

Gestión de dependencias GetX

La administración de dependencias de GetX es más simple y conveniente que Providero . InheritedWidgetPor ejemplo, tome la aplicación de contramuestra como ejemplo, use la administración de dependencias para modificarla y cumpla con los siguientes requisitos:

  • Cambiar de estado en cada clic
  • El estado se puede compartir entre diferentes páginas.
  • Separar la lógica empresarial de la interfaz

Paso 1: Definir una Controllerclase

class Controller extends GetxController{
    
    
  var count = 0.obs;
  increment() => count++;
  decrement() => count--;
}

Paso 2: crear y usar en la páginaController

class Home extends StatelessWidget {
    
    

  
  Widget build(context) {
    
      
  
    final Controller c = Get.put(Controller()); // 使用Get.put()实例化Controller,对所有子路由可用

    return Scaffold( 
      appBar: AppBar(title: Obx(() => Text("Clicks: ${
      
      c.count}"))), // 读取控制器中计数器的值
      body: Center(
      	child: ElevatedButton(
              child: Text("Go to Other"), 
              onPressed: () => Get.to(Other()) // 跳转Other页面
        )
      ),
      floatingActionButton: FloatingActionButton(
      	child: Icon(Icons.add), 
      	onPressed: c.increment // 调用控制器的方法修改计数器的值
      ));
  }
}

ControllerPaso 3: Obtenga el valor del contador compartido en otras páginas de enrutamiento

class Other extends StatelessWidget {
    
    
  
  final Controller c = Get.find(); // 通过 Get.find() 找到控制器对象

  
  Widget build(context){
    
    
     return Scaffold(body: Center(child: Text("${
      
      c.count}"))); // 访问控制器的计数变量
  }
}

Como puede ver, después de usar la administración de dependencias de GetX, es posible que ya no necesite usarla StatefulWidget. Es tan fácil que GetX acelera el desarrollo y entrega todo a tiempo sin sacrificar el rendimiento.

En resumen, GetX crea y adquiere controladores usando las siguientes dos líneas de código:

Controller controller = Get.put(Controller());  
Controller controller = Get.find();

Lo que tenemos que hacer es extraer las variables de datos dispersas en la página y la lógica de modificar las variables de datos en el Controllercontrolador.

Sí, parece magia, GetX encontrará su controlador y se lo dará. Puede instanciar un millón de controladores y GetX siempre le dará el correcto. Luego puede restaurar los datos del controlador que obtuvo más tarde.

Text(controller.textFromApi);

Imagine que ha navegado por innumerables rutas y ahora necesita obtener los datos que quedan en el controlador, GetX encontrará automáticamente los datos que desea para su controlador y ni siquiera necesita ninguna relación de dependencia adicional.

Consulte aquí para obtener más detalles sobre la gestión de dependencias .

Enlace GetX

Si todas las páginas necesitan usar administración de estado, sería demasiado problemático usar el método de crear instancias de controlador en cada página, Get.put(MyController())por lo que GetX proporciona una función de enlace más simple , que se puede configurar de manera global y uniforme, sin la necesidad de páginas separadas. Créalas uno a uno.

Primero comprendamos los muchos Controllermétodos de creación de instancias proporcionados por GetX, que se pueden seleccionar de acuerdo con diferentes negocios:

  • Get.put() : También se creará una instancia de controlador sin usarla
  • Get.lazyPut() : crea una instancia de forma diferida, solo cuando se usa
  • Get.putAsync() : una versión asíncrona de Get.put()
  • Get.create() : se creará una nueva instancia cada vez que se use

Echemos un vistazo a cómo usar la función Binding

Paso 1: Crea una Bindingclase

import 'package:get/get.dart';

class AllControllerBinding implements Bindings {
    
    
	
	void dependencies() {
    
     
		// 所有的 Controller 都在这里配置
		Get.lazyPut<BindingMyController>(() => BindingMyController()); // 懒加载方式
		Get.lazyPut<BindingHomeController>(() => BindingHomeController());
	}
}

Paso 2: GetMaterialAppinicialice el enlace en

return GetMaterialApp (
	initialBinding: AllControllerBinding(),
	home: GetXBindingExample(),
);

Get.find<MyController>()Paso 3: obtenga y use el administrador de estado en la página

Obx(() => Text(
	"计数器的值为 ${
      
      Get.find<BindingMyController>().count}",
	style: TextStyle(color: Colors.red, fontSize: 30),
)), 
ElevatedButton(
	onPressed: () {
    
    
		Get.find<BindingMyController>().increment();
	},
	child: Text("点击加1")
),

Enrutamiento + Enlace + GetView

Otra Bindingforma de usar GetX es vincularlo con el enrutamiento, lo que puede ahorrar Get.findpasos.

Paso 1: establezca el atributo en GetMaterialAppla tabla de enrutamiento de la configuraciónGetPagebinding

GetPage(
    name: "/shop",
    page: () => const ShopPage(),
    binding: ShopControllerBinding(), // 设置该页面的 Binding 
    middlewares: [ShopMiddleWare()]
),

Contenido de la misma ShopControllerBinding:

import 'package:get/get.dart';

import '../controllers/shop.dart';

class ShopControllerBinding implements Bindings{
    
    
  
  void dependencies() {
    
      
    Get.lazyPut<ShopController>(() => ShopController());
  }
}

ShopControllerContenido:

import 'package:get/get.dart';

class ShopController extends GetxController {
    
    
  RxInt counter = 10.obs;
  
  void inc() {
    
    
    counter.value++;
    update();
  }
}

Paso 2: ShopControllerHerencia en la página usadaGetView

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/shop.dart';

class ShopPage extends GetView<ShopController> {
    
    
  const ShopPage({
    
    super.key});
  
  Widget build(BuildContext context) {
    
       
    return Scaffold(
      appBar: AppBar(title: const Text('Title'),),
      body: Center(
        child: Column(
          children: [
            Obx(() => Text("${
      
      controller.counter}")),
            const SizedBox(height: 40,),
            ElevatedButton (
              onPressed: () {
    
     controller.inc();}, 
	          child: const Text("shop counter+1"))
          ],
        ),
      ),
    );
  }
}

De esta manera, no hay necesidad de escribir Get.findy puede usarlo directamente.

Pero debe tenerse en cuenta que de esta manera, cuando aparece la página de enrutamiento, la Controllerinstancia correspondiente se destruirá, mientras que otros métodos no se destruirán (intercambio global).

Ciclo de vida del controlador

El controlador en GetX tiene un ciclo de vida, que proporciona tres métodos de ciclo de vida:

  • onInit():widget se ejecuta inmediatamente cuando el componente de la página se crea desde la memoria y se puede usar para realizar servicios de inicialización, como solicitudes de datos iniciales de la página .
  • onReady(): llamado 1 cuadro después de onInit(), es un momento ideal para insertar eventos de navegación, como snackbar, diálogos o una nueva ruta o solicitud asincrónica.
  • onClose (): se llama cuando se destruye la página, se puede usar para limpiar recursos o guardar datos persistentes.
import 'package:get/get.dart';

class SearchController extends GetxController {
    
    
  RxList hotList=[].obs;

  void onInit() {
    
    
    print("请求接口数据");
    getHotList(); 
    super.onInit();
  }
  
  
  void onReady() {
    
    
    print("onReady");
    super.onReady();
  }	
  
  
  void onClose() {
    
    
    print("onClose");
    super.onClose();
  }

  void getHotList() {
    
      
    hotList.add("我是一个模拟的数据");
    update();
  }
}

Internacionalización de GetX y configuración de temas

globalización

Paso 1: Definir un paquete de idioma

import 'package:get/get.dart';

class Messages extends Translations {
    
    
  
  Map<String, Map<String, String>> get keys => {
    
    
        'zh_CN': {
    
    
          'hello': '你好 世界',
        },
        'de_DE': {
    
    
          'hello': 'Hallo Welt',
        }
      };
}

Paso dos: GetMaterialAppconfigurar en

  • traducciones : archivo de configuración de internacionalización
  • configuración regional : establezca el idioma predeterminado, si no se establece, será el idioma actual del sistema
  • fallbackLocale : agrega una opción de idioma de devolución de llamada en caso de que la traducción del idioma especificada anteriormente no exista
return GetMaterialApp(
    translations: Messages(), // 你的翻译语言包
    locale: Locale('zh', 'CN'), // 使用指定的语言翻译
    fallbackLocale: Locale('en', 'US'), // 指定的语言翻译不存在时的默认语言回调
);

Paso 3: al usar translate, cada vez que se agrega .trappend a la clave especificada, el valor actual de Get.localey se usará Get.fallbackLocalepara la traducción.

Text('title'.tr);

cambiar idioma

Llamado Get.updateLocale(locale)para actualizar la configuración regional. Entonces la traducción usará automáticamente la nueva locale.

var locale = Locale('en', 'US');
Get.updateLocale(locale);

Obtener idioma del sistema

Para leer el idioma del sistema, puede usar window.locale.

import 'dart:ui' as ui;

return GetMaterialApp(
    locale: ui.window.locale,
);

cambiar de tema

No GetMaterialAppactualice el tema con widgets de un nivel superior a este, lo que puede causar la duplicación de claves. Mucha gente está acostumbrada a crear un ThemeProviderwidget " " para cambiar el tema de la aplicación, lo cual es absolutamente innecesario en GetX™ .

Puede crear su tema personalizado y simplemente agregarlo Get.changeThemesin ninguna plantilla.

Get.changeTheme(ThemeData.light());

Si desea onTapcrear algo como un botón de cambio de tema en " ", puede combinar las dos API de GetX Get.changeTheme+ Get.isDarkModepara lograrlo. Puedes poner el siguiente código onPresseden .

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

Cuando darkmodeesté activado, cambiará al lighttema, y ​​cuando lightel tema esté activado, cambiará al darktema.

Otras funciones útiles

No es necesario pasar muchas llamadas de GetX context, lo cual es muy conveniente de usar.

método Función
Get.defaultDialog() mostrar ventanas emergentes
Get.snackbar() mostrar snackbar
Get.bottomSheet() Mostrar hoja inferior
Get.isSnackbarOpen Comprobar si la cafetería está abierta
Get.isDialogOpen Comprobar si el cuadro de diálogo está abierto
Get.isBottomSheetOpen Compruebe si la hoja inferior está abierta
Get.changeTheme() Alternar colores del tema
Get.isDarkMode Estilo de tema de juicio
Get.isAndroid
Get.isIOS
Get.isMacOS
Get.isWindows
Get.isLinux
Get.isFuchsia
Comprobar en qué plataforma se ejecuta la aplicación
Get.isMobile
Get.isDesktop
Get.isWeb
Verifique el tipo de dispositivo, tenga en cuenta que todas las plataformas admiten navegadores web de forma independiente
Get.height
Get.width
equivalente aMediaQuery.of(context).size.height
Get.context proporcionar el contexto actual
Get.contextOverlay En cualquier parte de su código, proporcione el contexto de snackbar/dialog/bottomsheet en primer plano

Los siguientes métodos son contextextensiones del contexto. Debido a que se puede acceder al contexto en cualquier parte de su interfaz de usuario, puede usarlo en cualquier parte de su código de interfaz de usuario.

método Función
context.width
context.width
Si necesita una altura/anchura modificable (como el escritorio o la ventana del navegador que se puede escalar), deberá usar el contexto
context.mediaQuerySize() Similar aMediaQuery.of(context).size
context.mediaQueryPadding() Similar aMediaQuery.of(context).padding
context.mediaQueryViewPadding() Similar aMediaQuery.of(context).viewPadding
context.mediaQueryViewInsets() Similar aMediaQuery.of(context).viewInsets
context.orientation() Similar aMediaQuery.of(context).orientation
context.devicePixelRatio Similar aMediaQuery.of(context).devicePixelRatio
context.textScaleFactor Similar aMediaQuery.of(context).textScaleFactor
context.mediaQueryShortestSide Consulta el lado más corto del dispositivo.
context.isLandscape() Comprobar si el dispositivo está en modo horizontal
context.isPortrait() Comprobar si el dispositivo está en modo vertical
context.heightTransformer()
context.widthTransformer()
让您可以定义一半的页面、三分之一的页面等。对响应式应用很有用。参数: dividedBy (double) 可选 - 默认值:1。参数: reducedBy (double) 可选 - 默认值:0。
context.showNavbar() 如果宽度大于800,则为真
context.isPhone() 如果最短边小于600p,则为真
context.isSmallTablet() 如果最短边大于600p,则为真
context.isLargeTablet() 如果最短边大于720p,则为真
context.isTablet() 如果当前设备是平板电脑,则为真
context.responsiveValue<T>() 根据页面大小返回一个值<T>可以给值为:
watch:如果最短边小于300
mobile:如果最短边小于600
tablet:如果最短边(shortestSide)小于1200
desktop:如果宽度大于1200

GetUtils

GetX 还提供了一个方便的工具类 GetUtils,里面提供了一些常用的方法,例如判断值是否为空、是否是数字、是否是视频、图片、音频、PPT、Word、APK、邮箱、手机号码、日期、MD5、SHA1等等。具体可以直接IDE查看 GetUtils类。

在这里插入图片描述

GetConnect

GetConnect可以便捷的通过httpwebsockets进行前后台通信。

默认配置

你能轻松的通过extend GetConnect就能使用GET/POST/PUT/DELETE/SOCKET方法与你的Rest APIwebsockets通信。

class UserProvider extends GetConnect {
    
    
  // Get request
  Future<Response> getUser(int id) => get('http://youapi/users/$id');
  // Post request
  Future<Response> postUser(Map data) => post('http://youapi/users', body: data);
  // Post request with File
  Future<Response<CasesModel>> postCases(List<int> image) {
    
    
    final form = FormData({
    
    
      'file': MultipartFile(image, filename: 'avatar.png'),
      'otherFile': MultipartFile(image, filename: 'cover.png'),
    });
    return post('http://youapi/users/upload', form);
  }

  GetSocket userMessages() {
    
    
    return socket('https://yourapi/users/socket');
  }
}

自定义配置

GetConnect具有多种自定义配置。你可以配置base Url,配置响应,配置请求,添加权限验证,甚至是尝试认证的次数,除此之外,还可以定义一个标准的解码器,该解码器将把您的所有请求转换为您的模型,而不需要任何额外的配置。

class HomeProvider extends GetConnect {
    
    
  
  void onInit() {
    
    
    // All request will pass to jsonEncode so CasesModel.fromJson()
    httpClient.defaultDecoder = CasesModel.fromJson;
    httpClient.baseUrl = 'https://api.covid19api.com';
    // baseUrl = 'https://api.covid19api.com'; // It define baseUrl to
    // Http and websockets if used with no [httpClient] instance

    // It's will attach 'apikey' property on header from all requests
    httpClient.addRequestModifier((request) {
    
    
      request.headers['apikey'] = '12345678';
      return request;
    });

    // Even if the server sends data from the country "Brazil",
    // it will never be displayed to users, because you remove
    // that data from the response, even before the response is delivered
    httpClient.addResponseModifier<CasesModel>((request, response) {
    
    
      CasesModel model = response.body;
      if (model.countries.contains('Brazil')) {
    
    
        model.countries.remove('Brazilll');
      }
    });

    httpClient.addAuthenticator((request) async {
    
    
      final response = await get("http://yourapi/token");
      final token = response.body['token'];
      // Set the header
      request.headers['Authorization'] = "$token";
      return request;
    });

    //Autenticator will be called 3 times if HttpStatus is
    //HttpStatus.unauthorized
    httpClient.maxAuthRetries = 3;
  }

  
  Future<Response<CasesModel>> getCases(String path) => get(path);
}

可选的全局设置和手动配置

GetMaterialApp为你配置了一切,但如果你想手动配置Get。

MaterialApp(
  navigatorKey: Get.key,
  navigatorObservers: [GetObserver()],
);

你也可以在GetObserver中使用自己的中间件,这不会影响任何事情。

MaterialApp(
  navigatorKey: Get.key,
  navigatorObservers: [
    GetObserver(MiddleWare.observer) // Here
  ],
);

你可以为 "Get "创建全局设置。只需在推送任何路由之前将Get.config添加到你的代码中。或者直接在你的GetMaterialApp中做。

GetMaterialApp(
  enableLog: true,
  defaultTransition: Transition.fade,
  opaqueRoute: Get.isOpaqueRouteDefault,
  popGesture: Get.isPopGestureEnable,
  transitionDuration: Get.defaultDurationTransition,
  defaultGlobalState: Get.defaultGlobalState,
);

Get.config(
  enableLog = true,
  defaultPopGesture = true,
  defaultTransition = Transitions.cupertino
)

你可以选择重定向所有来自Get的日志信息。如果你想使用你自己喜欢的日志包,并想查看那里的日志。

GetMaterialApp(
  enableLog: true,
  logWriterCallback: localLogWriter,
);

void localLogWriter(String text, {
    
    bool isError = false}) {
    
    
  // 在这里把信息传递给你最喜欢的日志包。
  // 请注意,即使enableLog: false,日志信息也会在这个回调中被推送。
  // 如果你想的话,可以通过GetConfig.isLogEnable来检查这个标志。
}

局部状态组件

这些Widgets允许您管理一个单一的值,并保持状态的短暂性和本地性。我们有Reactive和Simple两种风格。

例如,你可以用它们来切换TextField中的obscureText,也许可以创建一个自定义的可扩展面板(Expandable Panel),或者在"Scaffold "的主体中改变内容的同时修改BottomNavigationBar中的当前索引。

ValueBuilder

StatefulWidget的简化,它与setState回调一起工作,并接受更新的值。

ValueBuilder<bool>(
  initialValue: false,
  builder: (value, updateFn) => Switch(
    value: value,
    onChanged: updateFn, // 你可以用( newValue )=> updateFn( newValue )。
  ),
  // 如果你需要调用 builder 方法之外的东西。
  onUpdate: (value) => print("Value updated: $value"),
  onDispose: () => print("Widget unmounted"),
),

ObxValue

类似于ValueBuilder,但这是Reactive版本,你需要传递一个Rx实例(还记得神奇的.obs吗?自动更新…是不是很厉害?)

ObxValue((data) => Switch(
        value: data.value,
        onChanged: data, // Rx 有一个 _callable_函数! 你可以使用 (flag) => data.value = flag,
    ),
    false.obs,
),

有用的提示

.obs(也称为_Rx_ Types)有各种各样的内部方法和操作符。

var message = 'Hello world'.obs;
print( 'Message "$message" has Type ${
      
      message.runtimeType}');

即使message prints实际的字符串值,类型也是RxString所以,你不能做message.substring( 0, 4 )。你必须在_observable_里面访问真正的value。最常用的方法是".value", 但是你也可以用…

final name = 'GetX'.obs;
//只有在值与当前值不同的情况下,才会 "更新 "流。
name.value = 'Hey';

// 所有Rx属性都是 "可调用 "的,并返回新的值。
//但这种方法不接受 "null",UI将不会重建。
name('Hello');

// 就像一个getter,打印'Hello'。
name() ;

///数字。

final count = 0.obs;

// 您可以使用num基元的所有不可变操作!
count + 1;

// 注意!只有当 "count "不是final时,这才有效,除了var
count += 1;

// 你也可以与数值进行比较。
count > 2;

/// booleans:

final flag = false.obs;

// 在真/假之间切换数值
flag.toggle();


/// 所有类型。

// 将 "value "设为空。
flag.nil();

// 所有的toString()、toJson()操作都会向下传递到`value`。
print( count ); // 在内部调用 "toString() "来GetRxInt

final abc = [0,1,2].obs;
// 将值转换为json数组,打印RxList。
// 所有Rx类型都支持Json!
print('json: ${
      
      jsonEncode(abc)}, type: ${
      
      abc.runtimeType}');

// RxMap, RxList 和 RxSet 是特殊的 Rx 类型,扩展了它们的原生类型。
// 但你可以像使用普通列表一样使用列表,尽管它是响应式的。
abc.add(12); // 将12添加到列表中,并更新流。
abc[3]; // 和Lists一样,读取索引3。


// Rx和值是平等的,但hashCode总是从值中提取。
final number = 12.obs;
print( number == 12 ); // prints > true

///自定义Rx模型。

// toJson(), toString()都是递延给子代的,所以你可以在它们上实现覆盖,并直接打印()可观察的内容。

class User {
    
    
    String name, last;
    int age;
    User({
    
    this.name, this.last, this.age});

    
    String toString() => '$name $last, $age years old';
}

final user = User(name: 'John', last: 'Doe', age: 33).obs;

// `user`是 "响应式 "的,但里面的属性却不是!
// 所以,如果我们改变其中的一些变量:
user.value.name = 'Roi';
// 小部件不会重建! 
// 对于自定义类,我们需要手动 "通知 "改变。
user.refresh();

// 或者我们可以使用`update()`方法!
user.update((value){
    
    
  value.name='Roi';
});

print( user );

GetWidget

大多数人都不知道这个Widget,或者完全搞不清它的用法。这个用例非常少见且特殊:它 "缓存 "了一个Controller,因为cache,所以不能成为一个const Stateless

那么,什么时候你需要 "缓存 "一个Controller?

如果你使用了GetX的另一个 "不常见 "的特性 Get.create()

  • Get.create(()=>Controller()) 会在每次调用时生成一个新的Controller

Get.find<Controller>() 你可以用它来保存Todo项目的列表,如果小组件被 “重建”,它将保持相同的控制器实例。

GetxService

这个类就像一个 “GetxController”,它共享相同的生命周期(“onInit()”、“onReady()”、“onClose()”)。

但里面没有 “逻辑”。它只是通知GetX的依赖注入系统,这个子类不能从内存中删除。

所以这对保持你的 "服务 "总是可以被Get.find()获取到并保持运行是超级有用的。比如
ApiServiceStorageServiceCacheService

Future<void> main() async {
    
    
  await initServices(); /// 等待服务初始化.
  runApp(SomeApp());
}

/// 在你运行Flutter应用之前,让你的服务初始化是一个明智之举。
因为你可以控制执行流程(也许你需要加载一些主题配置,apiKey,由用户自定义的语言等,所以在运行ApiService之前加载SettingService。
///所以GetMaterialApp()不需要重建,可以直接取值。
void initServices() async {
    
    
  print('starting services ...');
  ///这里是你放get_storage、hive、shared_pref初始化的地方。
  ///或者moor连接,或者其他什么异步的东西。
  await Get.putAsync(() => DbService().init());
  await Get.putAsync(SettingsService()).init();
  print('All services started...');
}

class DbService extends GetxService {
    
    
  Future<DbService> init() async {
    
    
    print('$runtimeType delays 2 sec');
    await 2.delay();
    print('$runtimeType ready!');
    return this;
  }
}

class SettingsService extends GetxService {
    
    
  void init() async {
    
    
    print('$runtimeType delays 1 sec');
    await 1.delay();
    print('$runtimeType ready!');
  }
}

实际删除一个GetxService的唯一方法是使用Get.reset(),它就像"热重启 "你的应用程序。

所以如果你需要在你的应用程序的生命周期内对一个类实例进行绝对的持久化,请使用GetxService

GetX CLI和插件

GetX 提供了一个cli工具 Get CLI,通过该工具,无论是在服务器上还是在客户端,整个开发过程都可以完全自动化。

例如,Get CLI一个比较实用的功能是可以根据返回json的接口URL自动生成对应的Dart Model类

get generate [ModelName] on [Dir] from "https://api.github.com/users/CpdnCristiano"

此外,为了进一步提高您的生产效率,我们还为您准备了一些插件

GetX 原理机制

关于 GetX 的原理机制可以参考这篇文章:Flutter GetX深度剖析 该文作者已经写的非常详细了。这里不再赘述。

不过我们可以简单总结一下:

  • .obs的写法其实是利用了Dart的扩展语法,内部实现是一个具有callback以及运算符重载的数据类型
  • 当读取.obs数据类型的value变量值的时候(get value),会添加一个观察者进行监听
  • 当修改.obs数据类型的value变量值的时候(set value),则会触发监听回调,内部会获取value变量进一步执行 setState()自动刷新操作

简单来讲它就是 Dart的扩展语法 + 观察者模式 的应用,但是实现这样一个简洁的框架还是不简单的,从其代码中的层层包装和代理转发可见其复杂性。

Supongo que te gusta

Origin blog.csdn.net/lyabc123456/article/details/131054411
Recomendado
Clasificación