Administrator
Administrator
Published on 2025-06-11 / 2 Visits
0
0

GetX

国际化、依赖注入、状态管理、路由导航(不再显式传入BuildContext,任意位置可导航)、网络请求库

首先

flutter pub add get #安装依赖

将MaterialApp换成GetMaterialApp,GetMaterialApp是GetX预先封装配置好的一个组件,MaterialApp是它的子组件,并在此之上添加了一些属性。

全局状态/依赖注入

声明控制器class

class Controller extends GetxController {
  late SharedPreferences sharePreInstance;

  @override
  void onInit() async {
    super.onInit();
    await initGlobalState(); //初始化时进行数据的加载
  }


  var isLogin = false.obs; //添加.obs设为可观察对象,其类型变成RxBool
  void setIsLogin(bool v){
    token.value = v; //不可将bool直接赋值给RxBool,要用.value
  }

  Future<void> initGlobalState() async {
    sharePreInstance = await SharedPreferences.getInstance();
    setIsLogin(sharePreInstance.getBool("login") ?? false);
  }
}

注入控制器:

void main() async {
  Get.put(Controller());
  runApp(
      const MyApp()
  );
}

声明控制器变量方式1:

仅限StatelessWidget

class MyApp extends GetView<Controller> { // StatelessWidget改为用GetView<Controller>,Controller是上面声明的类,如果有多个控制器改为对应控制器
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Text("${controller.isLogin}");
  }
}

声明控制器变量方式2:

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  @override
  Widget build(BuildContext context) {
    final Controller c = Get.find();
    return /*Widget*/;
  }
}

声明控制器变量方式3:

class Test extends StatefulWidget {
  const Test({super.key});

  @override
  State<Test> createState() => _TestState();
}

class _TestState extends State<Test> {
  final Controller c = Get.find(); //StatefulWidget中可以声明在类成员属性
  
  @override
  Widget build(BuildContext context) {
    return /*Widget*/
  }
}

变量变化时自动刷新UI

需用Obx包裹,如果一个大区块内用到了多次控制器中的变量,则将整个容器放入Obx

Obx(()=>Text("count:${controller.count}"))

多语言

声明class

class MyTranslation extends Translations {
  @override
  Map<String, Map<String, String>> get keys => {
    'zh_CN': { //languageCode_countryCode,countryCode可省略,如:zh
      'hello': "你好",
      "nickname": "欢迎回来,用户:@user" //加入变量
    },
    'en_US': {
      'hello': "hello"
    }
  };
}

程序中注入

GetMaterialApp(
    //i18n
    translations: MyTranslation(),
    locale: Locale('zh', 'CN'),
    //...
  );

切换语言、获取当前语言

Get.updateLocale(Locale('en', 'US'));

Get.locale?.countryCode
Get.locale?.languageCode

UI中使用

Text("hello".tr); //加上.tr

Text("nickname".trParams({
      'user': username.value
    })); //加上.tr

网络请求库

编写class

import 'package:flutter_scan/main.dart';
import 'package:get/get.dart';

class ApiRequest extends GetConnect {
  final Controller c = Get.find(); //使用控制器中数据

  @override
  void onInit() {
    httpClient.baseUrl = "https://xxxx.cn";
    httpClient.timeout = Duration(seconds: 30);

    httpClient.addRequestModifier<void>((request){ //请求发送前的统一修改器
      if(c.isLogin.value) {
        request.headers["Authorization"] = "Bearer ${c.token}";
      }
      return request;
    });
    httpClient.addResponseModifier((request, response){ //响应收到时先进入修改器
      if(response.bodyString!.contains("登录信息无效")) {
        c.logout(); //控制器中的方法,做的事情就是清除本地存储、until一直返回到首页、清除控制器中存储的登录状态
        Get.snackbar("", "登录已经失效");
        throw Exception("登录失效"); //抛出错误,发起请求的地方会接收到null
      }

      return response; //没有登录失效则正常返回响应的内容
    });

    super.onInit();
  }
}

注入

void main() async {
  Get.put(Controller()); //如果api类中使用了控制器,就要先put控制器
  Get.put(ApiRequest());
  runApp(
      const MyApp()
  );
}

use

class _LoginPageState extends State<LoginPage>  {

  @override
  Widget build(BuildContext context) {
    final api = Get.find<ApiRequest>();
    return TextButton(onPress:() async {
      await api.post("/api/v1/login", LoginRequest(username: username, password: password, role: role).toString());
    }, child: Text("登录"));
  }
}

路由导航

Get.back(result: '返回给上一页的数据');  //返回到上一页

//在上层打开一个页面
Get.to(LoginPage());
Get.to("/login");
Get.toNamed("/login");


Get.until((route)=>route.settings.name == "/"); //一直返回,直到首页

Get.off(LoginPage()); //关闭当前页面,并打开对应页面
Get.off("/login"); //关闭当前页面,并打开对应页面
Get.offNamed("/login"); //关闭当前页面,然后打开login页面
Get.offAndToNamed("/login"); //关闭当前页面,然后打开login页面

Get.offAllNamed("/login"); //关闭所有页面,打开login页面(完成后页面栈只有login)
Get.offAll(LoginPage()); //关闭所有页面,打开指定页面(完成后页面栈只有login)
Get.offNamedUntil("/login", (route)=>route.settings.name=="/"); //一直退回到首页后打开login页面(完成后只有首页和login页面)
Get.offUntil(MaterialPageRoute(builder: (BuildContext context) { return LoginPage(); }), (route)=>route.settings.name=="/"); //退回到首页后通过Route<T>打开一个新页面


Comment