Bootstrap

从简单的demo开始让您逐步了解GetX的用法

目录

前言

一、从demo开始体现下Getx的用法

二、从最简单的功能开始

1.新建一个Flutter工程

2.GetX初体验

1.路由跳转

1.普通路由跳转

2.跳转并从堆栈中销毁当前页面

3.跳转并销毁之前所有页面

4.跳转以及传值

2.更方便的实现SnackBar、Dialog、BottomSheet

三、Getx完整的状态管理功能

1.GetBuilder

1.简单的计时器

2.使用GetBuilder的id参数局部更新

3.使用GetBuilder要注意的点

2.Obx

1.简单的计时器

2.多个响应式变量实例

3.总结

3.GetX小组件

4.GetX其它的一些实用功能

1.设置动画效果

2.国际化


前言

        这篇文章会从一个简单的工程开始,介绍下GetX的功能。

一、从demo开始体现下Getx的用法

        我们先看看getX的路由跳转功能,如下如1所示:

图1.GetX实现路由跳转功能

        在图1的过程中,我们实现了路由的跳转,以及路由跳转的时候从堆栈中移除当前页面的功能。

        在本篇博客的demo中,还提供了Getx路由跳转的传值功能,以及使用GetX实现SnackBar、Dialog,路由的别名跳转等功能。

图2.路由功能

图3.使用GetX实现Snackbar,Dialog,BottomSheet

二、从最简单的功能开始

        写这篇文章的时候,笔者的Flutter版本信息如下:

        图4.Flutter本地开发环境

1.新建一个Flutter工程

        本来想着一步一步的把创建的过程提出来的,仔细一想,这些基础的代码看到的兄弟们应该都会,这里直接贴出来新建的这个工程吧。

        不使用getx版本的实例代码在这里

        您可以下载下来看一下这些功能怎么实现,实在懒或者是感觉代码太简单的haul的话也可以在脑海中思考下这些功能的实现。

        下面我们来比较下如何使用Getx实现这些功能。

2.GetX初体验

        和其他的Flutter三方库一样,笔者这里用的getx的版本为4.6.6.首先我们应该在yaml文件中配置下getX。

get: ^4.6.6

        安装好之后,我们把MaterialApp改成GetMaterialApp即可在项目中使用GetX了。

1.路由跳转

1.普通路由跳转

        我们先看一下普通的路由跳转,例如在上面的例子中,普通的路由跳转我们应该这么写:

// 导航到 SecondPage
Navigator.push(context,MaterialPageRoute(builder: (context) => const SecondPage()),);

        很长的一段代码,使用get之后,代码如下:

Get.to(()=>const SecondPage());

        代码是不是简单了很多,而且不需要获取上下文的context(有些情况下获取context比较麻烦)。

2.跳转并从堆栈中销毁当前页面

        我们只需要下面一行代码即可:

Get.off(const ThirdPage());

        不使用GetX代码如下:

Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const ThirdPage()), );

3.跳转并销毁之前所有页面

        同样一样代码即可:

Get.offAll(const ThirdPage());

4.跳转以及传值

       当我们需要使用路由跳转并传值的时候,我们仅需要再GetMaterialApp中配置getPages属性,代码如下:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:state_management/fourth.dart';
import 'package:state_management/second.dart';
import 'package:state_management/third.dart';
import 'home.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),getPages: [
        GetPage(name: "/", page: ()=> const MyHomePage()),
        GetPage(
            name: "/second", page: ()=> const SecondPage(),
            transition: Transition.zoom
        ),
        GetPage(name: "/third", page: ()=> const ThirdPage()),
        GetPage(name: "/fourth", page: ()=> FourthPage()),
    ],
      home: const MyHomePage(),
    );
  }
}

        当我们需要跳转并传值的时候同样一行代码解决:

Get.toNamed("/fourth",arguments: "Something from second Screen");

        在需要接收传值的页面,使用下面的代码也可以一行代码解决:

Get.arguments != null ?Text("上一个页面传递的参数:${Get.arguments}"):const Text(''),

        我们还可以在当前页面接收下一个页面的会传值:

ElevatedButton(onPressed: () async { dataFromFourth = await Get.to(FourthPage()); setState(() { }); debugPrint("dataFromFourth:$dataFromFourth"); }, child: const Text('从第四个页面返回数据',style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold),),),

2.更方便的实现SnackBar、Dialog、BottomSheet

       使用getx,我们可以在不使用context的情况下使用很少代码实现Snackbar、dialog,BottomSheet。

        以SnackBar为例,一行代码搞定Snack:

Get.snackbar("GetX is Awesome", "您应该尝试使用它",snackPosition: SnackPosition.BOTTOM);

        不使用getx,代码如下:

ScaffoldMessenger.of(context).showSnackBar(
  const SnackBar(
    content: Text('这是一个 SnackBar!'),
  ),
);

        上述代码的Getx实现示例代码在这里

三、Getx完整的状态管理功能

        上一章节中,我们简单体验了GetX的以便方便之处,这一节我们将详细的讲解下Fluttter的状态管理功能。

1.GetBuilder

        这是一种手动状态管理器,内存消耗最小,使用较少的内存(接近0mb),当UI中的单独组件越多,性能越突出。

1.简单的计时器

        我们以计数器的效果为例,看一下GetBuilder的用法,在下面的实例中,我们点击count++按钮,计时器每次加1.

        图5.计时器实例

        我们看看如何实现图5的功能。

        首先我们创建一个GetxController用来保存计时器变量,这里要注意的是GetBuilder是手动状态管理器,我们需要主动的调用update方法,代码如下:

import 'package:get/get.dart';

class CounterController extends GetxController{
  int counter = 0;
  void increment(){
    counter++;
    update();
  }
}

        在使用GetBuilder的页面,我们只需要使用GetBuilder包裹住自己的Widget即可。

        我们通过Get.put方法获取GetxController实例。

final CounterController counterController = Get.put(CounterController());

        当我们点击按钮的时候,直接调用GetxController中的方法即可:

counterController.increment();

        完整的一个代码如下:

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

class StateManagementPage extends StatelessWidget {
  StateManagementPage({super.key});
  final CounterController counterController = Get.put(CounterController());


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.purple,
        title: const Text('GetX | StateManagement',style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 16),),
      ),
      body: Center(
        child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              GetBuilder<CounterController>(builder: (_){
                return Text("当前Count的值:${_.counter}");},
              ),
              // ElevatedButton(onPressed: (){}, child:Text('count++'',style: TextStyle(color: Colors.bold,))),
              const SizedBox(height: 20,),
              ElevatedButton(onPressed: (){
                counterController.increment();
              }, child: const Text('count+1',style: TextStyle(color: Colors.black,))),
              const SizedBox(height: 40,),
              ElevatedButton(onPressed: (){}, child: const Text('更新姓名和存储数量')),
            ]
        ),
      ),
    );
  }
}

        在上述的代码中,我们首先初始化了一个GetxController实例,然后调用该实例的increment方法,初次之外,我们还可以每次创建GetBuilder的时候,都调用GetxController的初始化方法,代码如下:

GetBuilder<CounterController>(builder: (_){
  return Text("当前Count的值:${_.counter}");
  },
  init: CounterController(),
),

        然后我们去ROM中查找GetxController,代码如下:

Get.find<CounterController>().increment();

        完整代码如下:

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

class StateManagementPage extends StatelessWidget {
  StateManagementPage({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.purple,
        title: const Text('GetX | StateManagement',style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 16),),
      ),
      body: Center(
        child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              GetBuilder<CounterController>(builder: (_){
                return Text("当前Count的值:${_.counter}");
                },
                init: CounterController(),
              ),
              // ElevatedButton(onPressed: (){}, child:Text('count++'',style: TextStyle(color: Colors.bold,))),
              const SizedBox(height: 20,),
              ElevatedButton(onPressed: (){
                Get.find<CounterController>().increment();
              }, child: const Text('count+1',style: TextStyle(color: Colors.black,))),
              const SizedBox(height: 40,),
              ElevatedButton(onPressed: (){}, child: const Text('更新姓名和存储数量')),
            ]
        ),
      ),
    );
  }
}

2.使用GetBuilder的id参数局部更新

        GetBuilder提供了一个id参数,用于局部更新界面。通过指定不同的id,可以实现更精细的控件刷新,避免整个页面刷新。

        我们以下面的demo为例:点击不同的按钮,更新不同的计数器:

       图6.使用GetBuilder参数局部更新

        在控制器中使用update指定id:

import 'package:get/get.dart';

class PartialRefreshController extends GetxController{
  int counter1 = 0;
  int counter2 = 0;

  void incrementCounter1(){
    counter1++;
    update(['counter1']); //只更新id为counter1的GetBuilder
    update();
  }
  void incrementCounter2(){
    counter2++;
    update(['counter2']); //只更新id为counter2的GetBuilder
  }

}

        在页面中使用不同的GetBuilder和id:

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

class PartialRefreshPage extends StatelessWidget {
  const PartialRefreshPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.purple,
        title: const Text('GetX | StateManagement',style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 16),),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const SizedBox(height: 40,),
            GetBuilder<PartialRefreshController>(
              id: 'counter1',
              builder: (controller) => Text('counter1: ${controller.counter1}'),
              init: PartialRefreshController(),
            ),
            const SizedBox(height: 40,),
            GetBuilder<PartialRefreshController>(
              id: 'counter2',
              builder: (controller) => Text('counter2: ${controller.counter2}'),
              init: PartialRefreshController(),
            ),
            const SizedBox(height: 40,),
            ElevatedButton(
              onPressed: () {
                Get.find<PartialRefreshController>().incrementCounter1();
              },
              child: const Text('counter1++'),
            ),
            const SizedBox(height: 40,),
            ElevatedButton(
              onPressed: () {
                Get.find<PartialRefreshController>().incrementCounter2();
              },
              child: const Text('counter2++'),
            ),
          ],
        )
      ),
    );
  }
}

3.使用GetBuilder要注意的点

  1. GetBuilder用于简单的状态管理,它是一个手动状态管理器,需要我们手动调用update方法更新页面
  2. 使用GetBuilder的时候,要确保对应的GetxController被初始化
  3. 使用 id 参数可以实现局部更新,减少不必要的界面重建。

2.Obx

        在 Flutter 中,Obx 是 GetX 提供的一种响应式小部件(widget),用于监听和响应数据变化。与 GetBuilder 不同,Obx 使用了 GetX 的响应式变量(Rx 类型),可以自动响应变量的变更并刷新对应的界面,不需要手动调用 update() 方法。Obx 的特点是简单、灵活,特别适合数据频繁变化的场景。

1.简单的计时器

        我们还以计时器代码为例:

        当我们使用Obx的时候,第一步先定义一个控制器,包含响应式变量counter和增加计数的方法。

import 'package:get/get.dart';

class CounterController extends GetxController {
  // 定义一个响应式变量
  var counter = 0.obs;

  // 增加计数的方法
  void increment() {
    counter++; // 更新变量,Obx 会自动响应变化
  }
}

        然后我们就可以在界面中使用Obx。

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'counter_controller.dart'; // 引入控制器

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 初始化控制器
    final CounterController counterController = Get.put(CounterController());

    return Scaffold(
      appBar: AppBar(
        title: Text('Obx 示例'),
      ),
      body: Center(
        child: Obx(() {
          // Obx 会自动监听 counter 变量的变化
          return Text(
            '点击次数: ${counterController.counter}',
            style: TextStyle(fontSize: 24),
          );
        }),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          counterController.increment(); // 调用 increment 更新 counter
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

2.多个响应式变量实例

        如果控制器中有多个响应式变量,每个变量改变时都会触发 Obx 的重建。

        控制器的代码如下:

import 'package:get/get.dart';

class MultiCounterController extends GetxController {
  var counter1 = 0.obs;
  var counter2 = 0.obs;

  void incrementCounter1() {
    counter1++;
  }

  void incrementCounter2() {
    counter2++;
  }
}

        在界面中分别用Obx监听counter1和counter2的变化。

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

class MultiCounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final MultiCounterController counterController = Get.put(MultiCounterController());

    return Scaffold(
      appBar: AppBar(title: Text('Obx 多变量示例')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Obx(() => Text('计数器1: ${counterController.counter1}', style: TextStyle(fontSize: 24))),
            Obx(() => Text('计数器2: ${counterController.counter2}', style: TextStyle(fontSize: 24))),
            ElevatedButton(
              onPressed: counterController.incrementCounter1,
              child: Text('增加计数器1'),
            ),
            ElevatedButton(
              onPressed: counterController.incrementCounter2,
              child: Text('增加计数器2'),
            ),
          ],
        ),
      ),
    );
  }
}

3.总结

  1. Obx 非常适合频繁变化的小范围状态管理,自动监听并响应 Rx(响应式)变量的变化。

  2. 使用 Obx 无需手动调用 update(),代码更简洁。

  3. 适合响应频繁或实时性较高的场景,比如计数器、表单输入等

3.GetX小组件

        在 Flutter 中使用 GetX 包装器可以直接在 UI 中使用 GetX 的响应式管理。你这里的代码使用 GetX 小部件来监听和显示 UserController 中 user 的数据变化。这种方法可以简化代码,将状态更新与 UI 绑定在一起。下面是完整的代码示例,解释如何通过 GetX 实现对用户数据的实时更新。

        我们以更新用户名称为例,看一下GetX小组件如何和UI绑定。

1.第一步:创建爱你UserController

import 'package:get/get.dart';

class User {
  String name;
  User({required this.name});
}

class UserController extends GetxController {
  // 创建一个响应式的 user 对象
  var user = User(name: 'John Doe').obs;

  // 更新用户名称的方法
  void updateUser(String newName) {
    user.update((val) {
      val?.name = newName;
    });
  }
}

2.第二步:在界面中使用GetX绑定数据

        在界面中使用 GetX<UserController> 小部件来监听 user 的变化。每当 user 的 name 属性发生变化时,Text 小部件将自动更新。

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'GetX Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: UserPage(),
    );
  }
}

4.GetX其它的一些实用功能

1.设置动画效果

        我们可以设置路由跳转时候的一些动画效果,例如缩放效果:

        图8.路由跳转缩放效果

        一行代码即可实现上述的功能:

Get.to(()=>const OtherPage(),transition: Transition.zoom);

2.国际化

        GetX提供了国际化的功能,我们只需要继承Translations,把要国际化的内容以键值对的形式放在字典里即可:

import 'package:get/get.dart';

class Messages extends Translations {
  @override
  Map<String, Map<String, String>> get keys => {
        'en_US': {
          'hello': 'Hello World',
        },
        'de_DE': {
          'hello': 'Hallo Welt',
        }
      };
}

        使用的时候,只要将.tr追加到指定的键上,就会使用Get.localeGet.fallbackLocale的当前值进行翻译。

Text('title'.tr);

        传递参数给GetMaterialApp来定义语言和翻译。

return GetMaterialApp(
    translations: Messages(), // 你的翻译
    locale: Locale('zh', 'CN'), // 将会按照此处指定的语言翻译
    fallbackLocale: Locale('en', 'US'), // 添加一个回调语言选项,以备上面指定的语言翻译不存在
);

        当我们需要修改语言的时候,调用Get.updateLocale(locale)来更新语言环境。然后翻译会自动使用新的locale。

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

        读取系统语言,使用window.locale。

import 'dart:ui' as ui;

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

;