Flutter_学习记录_状态管理之GetX

news2025/3/18 18:00:25

1. 状态管理、Flutter Getx介绍

1.1 状态管理

通俗的讲:当我们想在多个页面(组件/Widget)之间共享状态(数据),或者一个页面(组件/Widget)中的多个子组件之间共享状态(数据),这个时候我们就可以用Flutter中的状态管理来管理统一的状态(数据),实现不同组件之间的传值和数据共享。

现在Flutter的状态管理方案很多:redux、bloc、state、provider、Getx

provider是官方提供的状态管理解决方案,主要功能就是状态管理。
Getx是第三方的状态管理插件,不仅具有状态管理的功能,还具有路由管理、主题管理、国际化多语言管理、Obx局部更新、网络请求、数据验证等功能,相比其他状态管理插件Getx 简单、功能强大并且高性能。

1.2、Flutter Getx介绍

GetX 是 Flutter 上的一个轻量且强大的解决方案,Getx为我们提供了高性能的状态管理、智能的依赖注入和便捷的路由管理。

GetX 有3个基本原则

  • 性能: GetX 专注于性能和最小资源消耗。GetX 打包后的apk占用大小和运行时的内存占用与其他状态管理插件不相上下。
  • 效率: GetX 的语法非常简捷,并保持了极高的性能,能极大缩短你的开发时长。
  • 结构: GetX 可以将界面、逻辑、依赖和路由完全解耦,用起来更清爽,逻辑更清晰,代码更容易维护

GetX 并不臃肿,却很轻量。如果只使用状态管理,只有状态管理模块会被编译,其他没用到的东西都不会被编译到代码中。它拥有众多的功能,但这些功能都在独立的容器中,只有在使用后才会启动。

Getx有一个庞大的生态系统,能够在Android、iOS、Web、Mac、Linux、Windows和你的服务器上用同样的代码运行。 通过Get Server 可以在你的后端完全重用你在前端写的代码。

2. GetX 的简单使用

2.1 项目中集成GetX

官网:https://pub.dev/packages/get
中文文档:https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md

添加 GetX 的插件

在这里插入图片描述

导入头文件

import 'package:get/get.dart';

mian.dart 的文件中,将主入口的 MaterialApp 修改成GetMaterialApp

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

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

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

  
  Widget build(BuildContext context) {
  	//  `MaterialApp` 修改成`GetMaterialApp`
    return  GetMaterialApp(
      debugShowCheckedModeBanner: true,
      home: Home(),
      theme: ThemeData(
       appBarTheme: AppBarTheme(
         backgroundColor: Colors.yellow,
        )
      ),
    );
  }
}

2.2 显示GetX 默认的弹框defaultDialog

void _getXDefaultDialog() {
    Get.defaultDialog(
      title: "默认弹窗",
      middleText: "弹窗的内容",
      cancel: ElevatedButton(onPressed: (){
        Get.back();
      }, child: Text("取消")),
      confirm: ElevatedButton(onPressed: (){
        Get.back();
      }, child: Text("确认")),
      radius: 15.0
    );
  }

Dialog属性和说明
在这里插入图片描述

2.3 显示GetX Snackbar

void _getXSnackbar() {
    Get.snackbar(
      "提示标题", 
      "提示内容", 
      snackPosition: SnackPosition.BOTTOM,
      borderRadius: 10.0
    );
  }

Snackbar属性和说明

在这里插入图片描述
在这里插入图片描述

2.4 显示GetX BottomSheet

void _getXBottomSheet() {
    Get.bottomSheet(
      Container(
        color: Get.isDarkMode ? Colors.white12 :  Colors.white,
        height: 200,
        child: Column(
          children: [
            ListTile(
              onTap: (){
                // 改变主题模式
                Get.changeTheme(ThemeData.light());
                Get.back();
              },
              leading: Icon(Icons.sunny_snowing),
              title: Text("白天模式", style: TextStyle(color: Get.isDarkMode ? Colors.white : Colors.black),),
            ),
            ListTile(
              onTap: (){
                // 改变主题模式
                Get.changeTheme(ThemeData.dark());
                Get.back();
              },
              leading: Icon(Icons.dark_mode),
              title: Text("黑夜模式", style: TextStyle(color: Get.isDarkMode ? Colors.white : Colors.black)),
            )
          ],
        ),
      )
    );
  }

BottomSheet属性和说明
在这里插入图片描述

2.5 用GetX 修改主题模式

// 将主题修改成黑夜模式
Get.changeTheme(ThemeData.dark());
// 将主题修改成白天模式
Get.changeTheme(ThemeData.light());

3. GetX 的路由管理

3.1 Flutter Getx 配置路由以及动画

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

  
  Widget build(BuildContext context) {
    return  GetMaterialApp(
      debugShowCheckedModeBanner: true,
      // home: Home(),
      theme: ThemeData(
       appBarTheme: AppBarTheme(
         backgroundColor: Colors.yellow, // 设置导航栏颜色为蓝色
        )
      ),
      // 设置初始化页面
      initialRoute: "/",
      // 设置路由信息
      getPages:[
        GetPage(name: "/", page:  () => Home()),
        GetPage(name: "/login", page: () => GetLoginDemo()),
        GetPage(name: "/register", page: () => GetRegisterDemo()),
        GetPage(name: "/shop", page: () => GetShopDemo()),
        GetPage(name: "/shopMiddle", page: () => GetShopDemo(), middlewares: [GetShopmiddlewareDemo()]),
      ] ,
      // 设置跳转动画
      defaultTransition: Transition.rightToLeft,
    );
  }
}

代码解读

  • getPages 是一个数组,里面放着 GetPage类型的对象,name表示路由的名字, page 表示跳转的页面
  • initialRoute表示初始化的页面
  • defaultTransition 表示页面跳转的动画效果

3.2 GetX 跳转的常见方法:

调用to方法切换路由

Get.to(Home());

调用Get.toNamed()跳转到命名路由

// 不带参数的跳转
Get.toNamed("/login");
// 带参数的跳转
Get.toNamed("/shop",arguments: { 
	"id":20 
});

Getx 路由跳转传值以及接受数据

路由配置

	getPages:[
        GetPage(name: "/shop", page: () => GetShopDemo())
      ]

跳转传值

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

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

Get.back();

Get.offAll(); 返回到根

Get.offAll(Home());

进入下一个页面,但没有返回上一个页面的选项(用于闪屏页,登录页面等):Get.off(NextScreen());

3.3 Getx 中间件配置

新建一个Get_ShopMiddleware_demo.dart文件


import 'dart:math';

import 'package:flutter/src/widgets/navigator.dart';
import 'package:get/get.dart';

class  GetShopmiddlewareDemo extends GetMiddleware {
  //  重写跳转页面,例如点击购物,但是如果没有登录,就直接跳转登录页面;登录了就跳转商品页面

  
  RouteSettings? redirect(String? route) {
    print("redirect");

    int randomIndex = Random().nextInt(3);

    if (randomIndex == 1) {
      return super.redirect(route); 
    } else {
      return RouteSettings(name: "/login");
    }
  }
}

GetPage配置路由,在 middlewares 中添加中间件

// 设置路由信息
      getPages:[
        GetPage(name: "/shopMiddle", page: () => GetShopDemo(), middlewares: [GetShopmiddlewareDemo()]),
      ]

使用

 Get.toNamed("/shopMiddle", arguments: {
	 "id": 111111
});

4.Flutter Getx 状态管理

4.1 状态管理

目前,Flutter有几种状态管理器。但是,它们中的大多数都涉及到使用ChangeNotifier来更新widget,

这对于中大型应用的性能来说是一个很糟糕的方法。在Flutter的官方文档中查看到,ChangeNotifier应该使用1个或最多2个监听器,这使得它们实际上无法用于任何中等或大型应用

Get 并不是比任何其他状态管理器更好或更差,而是说分析这些要点以及下面的要点来选择只用Get,还是与其他状态管理器结合使用。

Get不是其他状态管理器的敌人,因为Get是一个微框架,而不仅仅是一个状态管理器,既可以单独使用,也可以与其他状态管理器结合使用。

Get有两个不同的状态管理器:响应式状态管理器、简单的状态管理器。

4.2 响应式状态管理器的使用

这部分的写作,参考的是这个文章:https://juejin.cn/post/7020598013986865182

4.2.1 声明响应式变量

  1. 使用 Rx{Type}
// 建议使用初始值,但不是强制性的
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>({});
  1. 使用 Rx规定泛型 Rx
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>();

3、这种更实用、更简单、更可取的方法,只需添加 .obs 作为value的属性。(推荐使用)

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;

4.2.2 自定义类的使用

第一种自定义类的使用:定义包含Rx属性的自定义类

// 1. 定义一个包含Rx属性的类型
class Person {
  RxString userName;
  RxInt age;

  Person({required this.userName, required this.age});
}

// 2. 声明变量
final Person _person = Person(userName: "猪猪".obs, age: 20.obs);

// 3. 使用
ListTile(
	// 用 Obx() 来更新局部的UI
	title: Obx((){
		return Text("person-姓名:${_person.userName}");
	}),
),

// 4. 改变数据:改变Person 的姓名字段
_person.userName.value = "${_person.userName} + 拼接$_count";

第二种自定义类的使用:常规属性的自定义类

// 1. 定义一个常规属性的自定义类
class Animal {
  String kindName;
  int count;

  Animal({required this.kindName, required this.count});
}

// 2. 声明变量
final Rx<Animal> _animal = Animal(kindName: "小猫", count: 1).obs;

// 3. 使用
ListTile(
// 用 Obx() 来更新局部的UI
	title: Obx((){
		return Text("animal-动物名:${_animal.value.kindName}");
	}),
)

// 4. 改变数据:改变Animal 的种类字段
_animal.value.kindName =  "${_animal.value.kindName} + 拼接$_count";
_animal.refresh();

4.2.3 完整案例

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

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

  
  State<GetDatastatusDemo> createState() => _GetDatastatusDemoState();
}

class _GetDatastatusDemoState extends State<GetDatastatusDemo> {

  // 1.1 定义int类型的数据
  final RxInt _count = 0.obs;
  // 2.1 定义String类型的数据
  final RxString _titleString = "这是字符串".obs;
  // 3.1 定义List<String> 类型的数据
  final List<String> _listString = ["1", "2"].obs;
  // 4.1 定义一个内部带有obs数据的模型
  final Person _person = Person(userName: "猪猪".obs, age: 20.obs);
  // 5.1 定义一个常规的模型
  final Rx<Animal> _animal = Animal(kindName: "小猫", count: 1).obs;


  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("数据的状态管理"),
      ),
      body: ListView(
        children: [
          ListTile(
            // 1.2 用 Obx() 来更新局部的UI
            title: Obx((){
              return Text("count: ${_count.value}");
            }),
          ),
          ListTile(
            // 2.2 用 Obx() 来更新局部的UI
            title: Obx((){
              return Text("字符串:$_titleString");
            }),
          ),
           ListTile(
            // 3.2 用 Obx() 来更新局部的UI
            title: Obx((){
              return Text("字符串:${_listString.toString()}");
            }),
          ),
          ListTile(
            // 4.2 用 Obx() 来更新局部的UI
            title: Obx((){
              return Text("person-姓名:${_person.userName}");
            }),
          ),
          ListTile(
            // 5.2 用 Obx() 来更新局部的UI
            title: Obx((){
              return Text("animal-动物名:${_animal.value.kindName}");
            }),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          // 1.3 改变数据
          _count.value ++;
          // 2.3 改变数据
          _titleString.value = "$_titleString + 拼接$_count";
          // 3.3 改变数据
          _listString.add("拼接$_count");
          // 4.3 改变Person 的姓名字段
          _person.userName.value = "${_person.userName} + 拼接$_count";
          // 5.3 改变Animal 的种类字段
          _animal.value.kindName =  "${_animal.value.kindName} + 拼接$_count";
          _animal.refresh();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

//-------定义一个内部变量为obs类型的模型类
class Person {
  RxString userName;
  RxInt age;

  Person({required this.userName, required this.age});
}


//-------定义一个常规模型
class Animal {
  String kindName;
  int count;

  Animal({required this.kindName, required this.count});
}

4.2.4 效果图如下:

在这里插入图片描述

4.3 Flutter Getx 简单的状态管理(依赖管理) GetxController 和 Binding

4.3.1 Getx 依赖管理简介

Get有一个简单而强大的依赖管理器,它允许你只用1行代码就能检索到与你的Bloc或Controller相同的类,无需Provider context,无需inheritedWidget。

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

Get会自动找到想要的数据,甚至不需要任何额外的依赖关系。

Controller controller = Get.find(); 
//是的,它看起来像魔术,Get会找到你的控制器,并将其提供给你。你可以实例化100万个控制器,Get 总会给你正确的控制器。

4.3.2 Binding

在我们使用 GetX 状态管理器的时候,往往每次都是用需要手动实例化一个控制器,这样的话基本页面都需要实例化一次,这样就太麻烦了,而 Binding 能解决上述问题,可以在项目初始化时把所有需要进行状态管理的控制器进行统一初始化,简单介绍一下几个最常用的:

Get.put(): 不使用控制器实例也会被创建
Get.lazyPut(): 懒加载方式创建实例,只有在使用时才创建
Get.putAsync(): Get.put() 的异步版版本
Get.create(): 每次使用都会创建一个新的实例

4.3.3 用GetxController 和 Binding 结合的使用

  1. 创建一个继承GetxController的控制器Countcontroller
import 'package:get/get.dart';

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

  void increase() {
    count++;
    // 需要调用update来通知更新
    update();
  }

  void decrease() {
    if (count > 1) {
      count--;
    }
    // 需要调用update来通知更新
    update();
  }
}
  1. 创建一个 实现Bindings 的控制器Bindcontroller
import 'package:demoapp/Demo/Get/CountController.dart';
import 'package:get/get.dart';

class Bindcontroller implements Bindings {
  
  void dependencies() {
  	//  用 lazyPut 关联 Countcontroller
    Get.lazyPut<Countcontroller>(() => Countcontroller());
  } 
}
  1. 在程序的入口(程序入口,需要将MaterialApp 修改成GetMaterialApp, 前面已经提到了),用initialBinding初始化Bindcontroller的值
import 'package:demoapp/Demo/Get/BindController.dart';
import 'package:demoapp/Router/AppRouter.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

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

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

  
  Widget build(BuildContext context) {
    return  GetMaterialApp(
      debugShowCheckedModeBanner: true,
      // home: Home(),
      theme: ThemeData(
       appBarTheme: AppBarTheme(
         backgroundColor: Colors.yellow, // 设置导航栏颜色为蓝色
        )
      ),
      // 设置初始化页面
      initialRoute: "/",
      // 设置路由信息
      getPages: Approuter.appRouterPages() ,
      // 设置跳转动画
      defaultTransition: Transition.rightToLeft,
      // 绑定控制器
      initialBinding: Bindcontroller(),
    );
  }
}
  1. 创建两个页面,来实现 页面数据的共享。
    功能:第一个页面获取到第二个页面的数据

第一个页面:

import 'package:demoapp/Demo/Get/CountController.dart';
import 'package:demoapp/Router/AppRouter.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class GetEasystatusDemo extends StatelessWidget {

  //  Get.find() 来找到共享的数据的页面,因为用了Bind 懒加载lazyput 所以不会出问题
  final Countcontroller _countCtr = Get.find();

  GetEasystatusDemo({super.key});

  // getX 简单式数据管理
  void _getXEasyDataStatus() {
  	// 用Get.toName 进行页面的跳转,Approuter.getEasyStatueTwoName 是抽取出来的页面的名字的定义,方便使用
    Get.toNamed(Approuter.getEasyStatueTwoName);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("简单的状态管理"),
      ),
      body: Center(child: Padding(
            padding: EdgeInsets.all(5),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              spacing: 20.0,
              children: [
                ElevatedButton(onPressed: _getXEasyDataStatus, child: Text("简单状态管理")),
                // 用obx 来刷新局部数据
                Obx((){ return Text("count = ${_countCtr.count}"); })
              ],
            ),
          )),
    );
  }
}

第二页页面:

import 'package:demoapp/Demo/Get/CountController.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class GetEasystatusSecondDemo extends StatelessWidget {
 //  Get.find() 来找到共享的数据的页面,因为用了Bind 懒加载lazyput 所以不用重新调用Get.put()方法
  final Countcontroller _countCtr = Get.find();

  GetEasystatusSecondDemo({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("简单的状态管理"),
      ),
      body: Center(
        child: Obx((){
          return Text("count = ${_countCtr.count}");
        })
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          // 让count +1
          _countCtr.increase();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

4.3.4 效果图如下

在这里插入图片描述

4.4 GetView 和 GetXController 和 Bindings 的结合使用

4.4.1 GetView 的介绍

GetView 只是对已注册的 Controller 有一个名为 controller 的getter的 const Stateless 的 Widget如果我们只有单个控制器作为依赖项,那我们就可以使用 GetView而不是使用StatelessWidget ,并且避免了写 Get.Find()

4.4.2 GetView 和 GetXController 和 Bindings结构的分析

  • GetView 主要是专注于页面的搭建和UI的更新
  • GetXController 主要是用于抽离数据, 维护和更新数据
  • Bindings 主要是懒加载GetXController,避免写Get.put(),让代码比较优雅

4.4.3 GetView 和 GetXController 和 Bindings 案例的使用

  1. 新建一个维护数据的GetXController
import 'package:get/get.dart';

class ShopController extends GetxController {
  RxList dataList = [].obs;

  
  void onInit() {
    print("onInit");
    super.onInit();
    getDataRequest();
  }

  
  void onClose() {
    print("onClose");
    super.onClose();
  }

  void getDataRequest() {
    dataList.add("新增数据");
  }
}
  1. 新建一个Bindings 的类
import 'package:demoapp/Demo/Get/Controller/ShopController.dart';
import 'package:get/get.dart';

class ShopBindings implements Bindings {
  
  void dependencies() {
    Get.lazyPut<ShopController>(() => ShopController());
  }
}
  1. 新建一个GetView的页面类:
    3.1 需要集成于: GetView
    3.2 需要关联:<ShopController>
    3.3 用 controller来获取 关联的 <ShopController>
    3.4 使用的时候,用controller来获取ShopController对应的数据与方法
    3.5 用obx来实现局部刷新

import 'package:demoapp/Demo/Get/Controller/ShopController.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class  GetShoppageDemo extends GetView<ShopController> {
  const GetShoppageDemo({super.key});

  
  Widget build(BuildContext context) {

    print(Get.arguments);

    return Scaffold(
      appBar: AppBar(
        title: Text("GetView的使用"),
      ),
      body: Obx((){
        return ListView(
          children: controller.dataList.map((value){
            return ListTile(
              title: Text(value),
            );
          }).toList(),
        );
      }),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          controller.getDataRequest();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}
  1. 配置路由:
    4.1 用binding字段将ShopBindings()关联上,这样就不需要在第3步的时候,单独写Get.put()方法,让代码更优雅一点。
// getShopPageName 这个是自己定义的字符串
GetPage(name: getShopPageName, page: ()=> GetShoppageDemo(), binding: ShopBindings()),

4.4.4 效果图

在这里插入图片描述

5. GetX 自定义语言包 国际化配置

在我们使用系统自带 MaterialApp 来实现国际化配置,需要进行很多配置,而且还需要手动去依赖第三方组件,而使用 GetX 来实现国际化配置,你只需要一行代码即可实现切换,接下来看一下具体实现。

5.1 定义一个语言包

import 'package:get/get_navigation/src/root/internacionalization.dart';

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

5.2 应用程序入口配置

  • translations: 国际化配置文件
  • locale: 设置默认语言,不设置的话为系统当前语言
  • fallbackLocale:添加一个回调语言选项,以备上面指定的语言翻译不存在
return GetMaterialApp(
  // 你的翻译 
   translations: Messages(), 
  // 将会按照此处指定的语言翻译 
  locale: Locale('zh', 'CN'), 
  // 添加一个回调语言选项,以备上面指定的语 言翻译不存在
  fallbackLocale: Locale('en', 'US'), 
);

5.3 调用语言包

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

Text('hello'.tr);

5.4 改变语言

调用 Get.updateLocale(locale) 来更新语言环境。然后翻译会自动使用新的locale。
更新后所有页面生效!

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

5.5 完整代码

import 'package:get/get.dart';

class Messages extends Translations {
  
  Map<String, Map<String, String>> get keys => {
        'zh_CN': {
          'hello': '你好 世界',
        },
        'de_DE': {
          'hello': 'Hallo Welt',
        }
      };
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import './language/message.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      translations: Messages(),
      locale: const Locale('zh', 'CN'),
      fallbackLocale: const Locale('en', 'US'),
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Title'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('title'.tr),
            const SizedBox(),
            Text('hello'.tr),
            ElevatedButton(
                onPressed: () {
                  var locale = const Locale('zh', 'CN');
                  Get.updateLocale(locale);
                },
                child: const Text("切换到中文")),
            const SizedBox(
              height: 20,
            ),
            ElevatedButton(
                onPressed: () {
                  var locale = const Locale('en', 'US');
                  Get.updateLocale(locale);
                },
                child: const Text("切换到英文")),
          ],
        ),
      ),
    );
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2317351.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络】数据流(Data Workflow)Routes(路由)、Controllers(控制器)、Models(模型) 和 Middleware(中间件)

在图片中&#xff0c;数据流&#xff08;Data Workflow&#xff09;描述了应用程序中数据的流动过程&#xff0c;涉及 Routes&#xff08;路由&#xff09;、Controllers&#xff08;控制器&#xff09;、Models&#xff08;模型&#xff09; 和 Middleware&#xff08;中间件&…

Git下载安装(保姆教程)

目录 1、Git下载 2、Git安装&#xff08;windows版&#xff09; &#xff08;1&#xff09;启动安装程序 &#xff08;2&#xff09;阅读许可协议 &#xff08;3&#xff09;选择安装路径 &#xff08;4&#xff09;选择组件 &#xff08;5&#xff09;选择开始菜单文件夹…

Blender-MCP服务源码2-依赖分析

Blender-MCP服务源码2-依赖分析 有个大佬做了一个Blender-MCP源码&#xff0c;第一次提交代码是【2025年3月7号】今天是【2025年月15日】也就是刚过去一周的时间&#xff0c;所以想从0开始学习这个代码&#xff0c;了解一下大佬们的开发思路 1-核心知识点 from mcp.server.fas…

LabVIEW压比调节器动态试验台

本案介绍了一种基于LabVIEW的压比调节器动态试验台的设计&#xff0c;通过实用的LabVIEW图形化编程语言&#xff0c;优化了数据采集与处理的整个流程。案例通过实际应用展示了设计的专业性与高效性&#xff0c;以及如何通过系统化的方法实现精确的动态测试和结果分析。 ​ 项目…

2025-03-17 Unity 网络基础1——网络基本概念

文章目录 1 网络1.1 局域网1.2 以太网1.3 城域网1.4 广域网1.5 互联网&#xff08;因特网&#xff09;1.6 万维网1.7 小结 2 IP 地址2.1 IP 地址2.2 端口号2.3 Mac 地址2.4 小结 3 客户端与服务端3.1 客户端3.2 服务端3.3 网络游戏中的客户端与服务端 1 网络 ​ 在没有网络之前…

springboot441-基于SpringBoot的校园自助交易系统(源码+数据库+纯前后端分离+部署讲解等)

&#x1f495;&#x1f495;作者&#xff1a; 爱笑学姐 &#x1f495;&#x1f495;个人简介&#xff1a;十年Java&#xff0c;Python美女程序员一枚&#xff0c;精通计算机专业前后端各类框架。 &#x1f495;&#x1f495;各类成品Java毕设 。javaweb&#xff0c;ssm&#xf…

浅谈数据分析及数据思维

目录 一、数据分析及数据分析思维&#xff1f;1.1 数据分析的本质1.2 数据分析思维的本质1.2.1 拥有数据思维的具体表现1.2.2 如何培养自己的数据思维1.2.2.1 书籍1.2.2.2 借助工具1.2.2.3 刻意练习 二、数据分析的价值及必备能力&#xff1f;2.1 数据分析的价值2.1.1 现状分析…

自定义uniapp组件,以picker组件为例

编写目的 本文说明基于vue3定义uniapp组件的关键点&#xff1a; 1、一般定义在components文件夹创建组件&#xff0c;组件与页面已经没有明确的语法格式区别&#xff0c;所以可以与页面的语法保持一致 &#xff1b; 2、组件定义后使用该组件的页面不需要引用组件即可使用&am…

【操作系统安全】任务4:Windows 系统网络安全实践里常用 DOS 命令

目录 一、引言 二、网络信息收集类命令 2.1 ipconfig 命令 2.1.1 功能概述 2.1.2 实例与代码 2.2 ping 命令 2.2.1 功能概述 2.2.2 实例与代码 2.3 tracert 命令 2.3.1 功能概述 2.3.2 实例与代码 三、网络连接与端口管理类命令 3.1 netstat 命令 3.1.1 功能概述…

【从零开始学习计算机科学】信息安全(二)物理安全

【从零开始学习计算机科学】信息安全(二)物理安全 物理安全物理安全的涵义物理安全威胁常见物理安全问题物理安全需求规划物理安全需求设备安全防盗和防毁机房门禁系统机房入侵检测和报警系统防电磁泄漏防窃听设备管理设备维护设备的处置和重复利用设备的转移电源安全电源调整…

LeetCode hot 100—验证二叉搜索树

题目 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 示例 示例 1&#…

MongoDB 可观测性最佳实践

MongoDB 介绍 MongoDB 是一个高性能、开源的 NoSQL 数据库&#xff0c;它采用灵活的文档数据模型&#xff0c;非常适合处理大规模的分布式数据。MongoDB 的文档存储方式使得数据结构可以随需求变化而变化&#xff0c;提供了极高的灵活性。它支持丰富的查询语言&#xff0c;允许…

论文阅读笔记——LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS

LoRA 论文 传统全面微调&#xff0c;对每个任务学习的参数与原始模型相同&#xff1a; m a x Φ ∑ ( x , y ) ∈ Z ∑ t 1 ∣ y ∣ l o g ( P Φ ( y t ∣ x , y < t ) ) 式(1) max_{\Phi}\sum_{(x,y)\in Z}\sum^{|y|}_{t1}log(P_{\Phi}(y_t|x,y<t)) \qquad \text{式(…

UE5中 Character、PlayerController、PlayerState、GameMode和GameState核心类之间的联动和分工·

1. GameMode 与 GameState 关系描述 GameMode&#xff1a;定义游戏规则和逻辑&#xff0c;控制游戏的开始、进行和结束。GameState&#xff1a;存储和同步全局游戏状态&#xff0c;如得分、时间、胜利条件等。 联动方式 GameMode初始化GameState&#xff1a;GameMode在游戏…

Ubuntu24.04 启动后突然进入tty,无法进入图形界面

问题描述 昨晚在编译 Android AOSP 14 后&#xff0c;进入了登录页面&#xff0c;但出现了无法输入密码的情况&#xff0c;且无法正常关机&#xff0c;只能强制重启。重启后&#xff0c;系统只能进入 TTY 页面&#xff0c;无法进入图形界面。 问题排查 经过初步排查&#x…

搭建主从服务器

任务需求 客户端通过访问 www.nihao.com 后&#xff0c;能够通过 dns 域名解析&#xff0c;访问到 nginx 服务中由 nfs 共享的首页文件&#xff0c;内容为&#xff1a;Very good, you have successfully set up the system. 各个主机能够实现时间同步&#xff0c;并且都开启防…

jenkins 配置邮件问题整理

版本&#xff1a;Jenkins 2.492.1 插件&#xff1a; A.jenkins自带的&#xff0c; B.安装功能强大的插件 配置流程&#xff1a; 1. jenkins->系统配置->Jenkins Location 此处的”系统管理员邮件地址“&#xff0c;是配置之后发件人的email。 2.配置系统自带的邮件A…

JVM中常量池和运行时常量池、字符串常量池三者之间的关系

文章目录 前言常量池&#xff08;Constant Pool&#xff09;运行时常量池&#xff08;Runtime Constant Pool&#xff09;字符串常量池&#xff08;String Literal Pool&#xff09;运行时常量池和字符串常量池位置变化方法区与永久代和元空间的关系三者之间的关系常量池与运行…

Mysql篇——SQL优化

本篇将带领各位了解一些常见的sql优化方法&#xff0c;学到就是赚到&#xff0c;一起跟着练习吧~ SQL优化 准备工作 准备的话我们肯定是需要一张表的&#xff0c;什么表都可以&#xff0c;这里先给出我的表结构&#xff08;表名&#xff1a;userinfo&#xff09; 通过sql查看…

FPGA|Verilog-SPI驱动

最近准备蓝桥杯FPGA的竞赛&#xff0c;因为感觉官方出的IIC的驱动代码思路非常好&#xff0c;写的内容非常有逻辑并且规范。也想学习一下SPI的协议&#xff0c;所以准备自己照着写一下。直到我打开他们给出的SPI底层驱动&#xff0c;我整个人傻眼了&#xff0c;我只能说&#x…