Flutter-Getx的使用

依赖

dependencies:
  get:

导入

import 'package:get/get.dart';

1.全局配置

MaterialApp --》 GetMaterialApp

GetMaterialApp不是使用Get的必要项

如果你只是使用 Get 进行状态管理或依赖管理,则不需要使用 GetMaterialApp。

GetMaterialApp 对于路由、通知栏、国际化、底部弹出窗口、对话框以及与路由和缺少上下文相关的高层 API 是必需的

 

2.简化代码

任何可观测对象都使用.obs修饰

class Controller {
  var count = 0.obs;
}

让所有子界面共用数据

final Controller c = Get.put(Controller());
final Controller c = Get.find();

需要使用obx装饰部件

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

3.状态管理 https://github.com/jonataslaw/getx/blob/master/documentation/en_US/state_management.md

简单状态管理和响应式管理 

声明可观察的变量-3种方式

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>({});
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>();
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;

使用View监听值

GetX<Controller>(
  builder: (controller) {
    print("count 1 rebuild");
    return Text('${controller.count1.value}');
  },
)

把值变成状态管理值的两种方式

class RxUser {
  final name = "Camila".obs;
  final age = 18.obs;
}
class User {
  User({String name, int age});
  var name;
  var age;
}

final user = User(name: "Camila", age: 18).obs;

自定义类值的更新

class User() {
  User({this.name = '', this.age = 0});
  String name;
  int age;
}

final user = User().obs;

//更新方式一 user.update( (user) { // this parameter is the class itself that you want to update user.name = 'Jonny'; user.age = 18; });
//更新方式二
user(User(name: 'João', age: 35)); 
//使用方式一
Obx(()=> Text("Name ${user.value.name}: Age: ${user.value.age}"))

//使用方式二
user().name;

监听值更改的回调

/// 每次更改都回调
ever(count1, (_) => print("$_ has been changed")); /// 监听一次 once(count1, (_) => print("$_ was changed once")); /// 防抖,键入结束时触发 debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1)); /// 忽略所有更改 interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1));

简单的状态管理使用

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

GetBuilder<Controller>(
  init: Controller(), 
  builder: (_) => Text(
    '${_.counter}',
  ),
)

在其他地方使用同一个Controller

class Controller extends GetxController {

  static Controller get to => Get.find();

}

GetBuilder包含了StatefulWidgets的所有方法

GetBuilder<Controller>(
  initState: (_) => Controller.to.fetchApi(),
  dispose: (_) => Controller.to.closeStreams(),
  builder: (s) => Text('${s.username}'),
),

通过指定id表明只更新某个部件

update(['text']);

状态管理部件总结

GetBuilder vs GetX vs Obx vs MixinBuilder

4.路由管理 https://github.com/jonataslaw/getx/blob/master/documentation/en_US/route_management.md

Get.to(NextScreen());

Get.toNamed('/details');

Get.back();

Get.off(NextScreen()); //关闭当前页面并进入指定界面

Get.offAll(NextScreen());

 配置

void main() {
  runApp(
    GetMaterialApp(
      initialRoute: '/',
      getPages: [
        GetPage(name: '/', page: () => MyHomePage()),
        GetPage(name: '/second', page: () => Second()),
        GetPage(
          name: '/third',
          page: () => Third(),
          transition: Transition.zoom  
        ),
      ],
    )
  );
}

发送参数

Get.toNamed("/NextScreen", arguments: 'Get is the best');

Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");

接受参数

print(Get.parameters['id']);
// out: 354
print(Get.parameters['name']);
// out: Enzo
print(Get.arguments);
 

路由监听

GetMaterialApp(
  routingCallback: (routing) {
    if(routing.current == '/second'){
      openAds();
    }
  }
)

小部件

Get.snackbar('Hi', 'i am a modern snackbar');
Get.rawSnackbar();
Get.dialog(YourDialogWidget());

await Get.defaultDialog( //使用await等待返回结果
  onConfirm: () => print("Ok"),
  middleText: "Dialog made in 3 lines of code"
);

Get.generalDialog(pageBuilder: (_,__,___){
return Text('data');
});

Get.bottomSheet();
 

 

5.依赖管理 https://github.com/jonataslaw/getx/blob/master/documentation/en_US/dependency_management.md

final Controller c = Get.put(Controller());
final Controller c = Get.find();

实例化Controller

Get.put<S>(
  // 必备:你想得到保存的类,比如控制器或其他东西。
  // 注:"S "意味着它可以是任何类型的类。
  S dependency

  // 可选:当你想要多个相同类型的类时,可以用这个方法。
  // 因为你通常使用Get.find<Controller>()来获取一个类。
  // 你需要使用标签来告诉你需要哪个实例。
  // 必须是唯一的字符串
  String tag,

  // 可选:默认情况下,get会在实例不再使用后进行销毁
  // (例如:一个已经销毁的视图的Controller)
  // 但你可能需要这个实例在整个应用生命周期中保留在那里,就像一个sharedPreferences的实例或其他东西。
  //所以你设置这个选项
  // 默认值为false
  bool permanent = false,

  // 可选:允许你在测试中使用一个抽象类后,用另一个抽象类代替它,然后再进行测试。
  // 默认为false
  bool overrideAbstract = false,

  // 可选:允许你使用函数而不是依赖(dependency)本身来创建依赖。
  // 这个不常用
  InstanceBuilderCallback<S> builder,
)

按需实例化Controller

Get.lazyPut<S>(
  // 强制性:当你的类第一次被调用时,将被执行的方法。
  InstanceBuilderCallback builder,
  
  // 可选:和Get.put()一样,当你想让同一个类有多个不同的实例时,就会用到它。
  // 必须是唯一的
  String tag,

  // 可选:类似于 "永久",
  // 不同的是,当不使用时,实例会被丢弃,但当再次需要使用时,Get会重新创建实例,
  // 就像 bindings api 中的 "SmartManagement.keepFactory "一样。
  // 默认值为false
  bool fenix = false
  
)

 

Get.putAsync<S>(

  // 必备:一个将被执行的异步方法,用于实例化你的类。
  AsyncInstanceBuilderCallback<S> builder,

  // 可选:和Get.put()一样,当你想让同一个类有多个不同的实例时,就会用到它。
  // 必须是唯一的
  String tag,

  // 可选:与Get.put()相同,当你需要在整个应用程序中保持该实例的生命时使用。
  // 默认值为false
  bool permanent = false
)

使用create方法

Get.create<S>(
  // 需要:一个返回每次调用"Get.find() "都会被新建的类的函数。
  // 示例: Get.create<YourClass>(()=>YourClass())
  FcBuilderFunc<S> builder,

  // 可选:就像Get.put()一样,但当你需要多个同类的实例时,会用到它。
  // 当你有一个列表,每个项目都需要自己的控制器时,这很有用。
  // 需要是一个唯一的字符串。只要把标签改成名字
  String name,

  // 可选:就像 Get.put() 一样,
  // 它是为了当你需要在整个应用中保活实例的时候
  // 区别在于 Get.create 的 permanent默认为true
  bool permanent = true

使用Controller

final controller = Get.find<Controller>();
// 或者
Controller controller = Get.find();

移除Controller

Get.delete<Controller>(); //通常你不需要这样做,因为GetX已经删除了未使用的控制器。

使用Bindings进行View和Controller的结合

class HomeBinding implements Bindings {
  @override
  void dependencies() {
    Get.lazyPut<HomeController>(() => HomeController());
    Get.put<Service>(()=> Api());
  }
}
getPages: [
  GetPage(
    name: '/',
    page: () => HomeView(),
    binding: HomeBinding(),
  ),
  GetPage(
    name: '/details',
    page: () => DetailsView(),
    binding: DetailsBinding(),
  ),
];


getPages: [
  GetPage(
    name: '/',
    page: () => HomeView(),
    binding: BindingsBuilder(() {
      Get.lazyPut<ControllerX>(() => ControllerX());
      Get.put<Service>(()=> Api());
    }),
  ),
  GetPage(
    name: '/details',
    page: () => DetailsView(),
    binding: BindingsBuilder(() {
      Get.lazyPut<DetailsController>(() => DetailsController());
    }),
  ),
];
 
Get.to(Home(), binding: HomeBinding());
Get.to(DetailsView(), binding: DetailsBinding())

6.国际化

定义

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',
        }
      };
}

使用

Text('title'.tr);

带参数

import 'package:get/get.dart';


Map<String, Map<String, String>> get keys => {
    'en_US': {
        'logged_in': 'logged in as @name with email @email',
    },
    'es_ES': {
       'logged_in': 'iniciado sesión como @name con e-mail @email',
    }
};

Text('logged_in'.trParams({
  'name': 'Jhon',
  'email': 'jhon@example.com'
  }));

需要配置

return GetMaterialApp(
    translations: Messages(), 
    locale: Locale('en', 'US'), 
    fallbackLocale: Locale('en', 'UK'),//默认的语言
);

动态更改语言


Get.deviceLocale;//获取系统语言
var locale = Locale('en', 'US');
Get.updateLocale(locale);

7.更改主题

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

//个人建议
//如果只是更新暗夜模式使用dartMode
Get.changeThemeMode(Get.isDarkMode ? ThemeMode.light : ThemeMode.dark);
//注意这种方式必须在GetMaterialApp中添加theme和dartTheme
GetMaterialApp(home: MyPage(), theme: ThemeData.light(), darkTheme: ThemeData.dark(),)

8.网络请求

class HomeProvider extends GetConnect {
  @override
  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;
  }

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

9.路由中间件

强大的路由拦截机制,允许你在页面导航前后执行自定义逻辑(如权限验证、日志记录、数据预加载等)

 10.其他的便捷属性

Get.arguments //获取传递的参数
Get.previousRoute //上一个路由
Get.rawRoute //根路由
Get.routing //路由信息
Get.isSnackbarOpen 
Get.isDialogOpen
Get.isBottomSheetOpen
Get.removeRoute() //移除某个路由
Get.until() //关闭页面直到条件为true
Get.offUntil() //关闭页面直到条件为true,并且打开一个新的路由
Get.offNamedUntil() //同上

//获取平台信息
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
GetPlatform.isMobile
GetPlatform.isDesktop
GetPlatform.isWeb
//宽高(不可变)
Get.height
Get.width

//上下文
Get.context
//弹窗上下文
Get.contextOverlay
//宽高(可变)
context.width
context.height
//宽高的倍数
context.heightTransformer()
context.widthTransformer()
//等同于
MediaQuery所使用的api
context.mediaQuerySize()
context.mediaQueryPadding()
context.mediaQueryViewPadding()
context.mediaQueryViewInsets()
context.orientation()
context.isLandscape()
context.isPortrait()
context.devicePixelRatio() 
context.textScaleFactor()
context.mediaQueryShortestSide() //最短边,用于判断是手机还是平板
context.showNavbar()
context.isPhone() //是否是手机
context.isSmallTablet()
context.isLargeTablet()
context.isTablet() //是否是平板
/// watch: if the shortestSide is smaller than 300
/// mobile: if the shortestSide is smaller than 600
/// tablet: if the shortestSide is smaller than 1200
/// desktop: if width is largest than 1200
context.responsiveValue<T>()

11.Get的全局属性更改

//需要放在第一个路由的前面
Get.config( enableLog
= true, defaultPopGesture = true, defaultTransition = Transitions.cupertino )

12.状态管理部件

部件内部更新-简单值

ValueBuilder<bool>(
  initialValue: false,
  builder: (value, updateFn) => Switch(
    value: value,
    onChanged: updateFn, 
  ),
  onUpdate: (value) => print("Value updated: $value"),
  onDispose: () => print("Widget unmounted"),
),

obs动态变换

ObxValue((data) => Switch(
        value: data.value,
        onChanged: data, 
    ),
    false.obs,
),

13.更改和获取 .obs 的值

//字符串类型
final name = 'GetX'.obs;
name.value = 'Hey';
name('Hello');
name() ;

//数字类型
final count = 0.obs;
count + 1;
count > 2;
//布尔值
final flag = false.obs;
flag.toggle();
//集合类型,像普通集合类型一样用就好了
final abc = [0,1,2].obs;
abc.add(12);
abc[3];
//对象类型
class User {
    String name, last;
    int age;
    User({this.name, this.last, this.age});

    @override
    String toString() => '$name $last, $age years old';
}
final user = User(name: 'John', last: 'Doe', age: 33).obs;
user.value.name = 'Roi';
user.refresh(); //必须调用才能实现界面刷新
user.update((value){ //或者调用这个
  value.name='Roi';
});

14.StateMixin 适合更新整个数据对象,界面可自动包含加载中,加载成功,加载失败,空数据

class Controller extends GetController with StateMixin<User>{}
change(data, status: RxStatus.success());
class OtherClass extends GetView<Controller> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: controller.obx(
        (state)=>Text(state.name),
        onLoading: CustomLoadingIndicator(),
        onEmpty: Text('No data found'),
        onError: (error)=>Text(error),
      ),
    );
}

15.GetView:要使用GetController需要结合GetView使用

 class AwesomeController extends GetController {
   final String title = 'My Awesome View';
 }

 class AwesomeView extends GetView<AwesomeController> {
   @override
   Widget build(BuildContext context) {
     return Container(
       padding: EdgeInsets.all(20),
       child: Text(controller.title), 
     );
   }
 }

16.GetResponsiveView:可针对不同的设备类型构建不同的布局

class MyPage extends GetResponsiveView<Controller> {
  MyPage({super.key});


  @override
  Widget desktop() {
    
  }


  @override
  Widget phone() {

  }

  @override
  Widget tablet() {

  }

  @override
  Widget watch() {

  }
}
17.GetWidget配合Get.create()使用:适合需要独立控制器实例的临时页面或组件
GetWidget<FormController>(
  init: Get.create<FormController>(() => FormController()),
  autoRemove: true,
  onDispose: (controller) {
    controller.saveDraft(); // 销毁前自动保存草稿
  },
  builder: (controller) => /*...*/,
)

18.跟应用生命周期相同的实例 GetxService

Future<void> main() async {
  await initServices();
  runApp(SomeApp());
}

void initServices() async {
  print('starting services ...');
  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!');
  }
}

销毁只能调用 Get.reset()

 
posted @ 2025-07-05 16:46  呢哇哦比较  阅读(127)  评论(0)    收藏  举报