关于Get

  • GetX 是 Flutter 上的一个轻量且强大的解决方案:高性能的状态管理、智能的依赖注入和便捷的路由管理。

  • GetX 有3个基本原则:

  • 性能: GetX 专注于性能和最小资源消耗。GetX 打包后的apk占用大小和运行时的内存占用与其他状态管理插件不相上下。如果你感兴趣,这里有一个性能测试

  • 效率: GetX 的语法非常简捷,并保持了极高的性能,能极大缩短你的开发时长。

  • 结构: GetX 可以将界面、逻辑、依赖和路由完全解耦,用起来更清爽,逻辑更清晰,代码更容易维护。

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

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

依赖注入

//controller.dart
class Controller extends GetxController{
  var count = 0.obs;
  increment() => count++;
}


//view.dart

class Home extends StatelessWidget {

  @override
  Widget build(context) {

    // 使用Get.put()实例化你的类,使其对当下的所有子路由可用。
    final Controller c = Get.put(Controller());

    return Scaffold(
      // 使用Obx(()=>每当改变计数时,就更新Text()。
      appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),

      // 用一个简单的Get.to()即可代替Navigator.push那8行,无需上下文!
      body: Center(child: ElevatedButton(
              child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
      floatingActionButton:
          FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
  }
}

class Other extends StatelessWidget {
  // 你可以让Get找到一个正在被其他页面使用的Controller,并将它返回给你。
  final Controller c = Get.find();

  @override
  Widget build(context){
     // 访问更新后的计数变量
     return Scaffold(body: Center(child: Text("${c.count}")));
  }
}

GET组件

Get.snackbar 通知提示框

RaisedVutton(
  child:Text('snackbar'),
  onPressed:(){
  	Get.snackbar("标题","网络错误!",
        colorText:Colors.white,backgroundColor:Colors.black54);
  }
)

Get.defaultDialog弹出提示框

RaisedVutton(
  child:Text('defaultDialog'),
  onPressed:(){
  	Get.defaultDialog(
      title:'标题'
      titleStyle:TextStyle(color:Colors.red),
      content:Column(
      	children:[
          Text('内容')
          Text('内容')
          Text('内容')
          Text('内容')
          Text('内容')
        ]
      ),
      cancel:RaisedButton(
      	child:Text('取消'),
        onPressed:(){
        	Get.back();
        }
      ),
      confirm:RaisedButton(
        color:Colors.green
      	child:Text('确定',
                  style:TextStyle(Colors.white)),
        onPressed:(){
          Get.back();
        	Get.snackbar("提示","消息已确认!")
        }
      ),
      barrierDismissible:false //点击空白处diglog不关闭
      
    );
  }
)

Get.bottomSheet底部弹出框

RaisedButton(
  child:Text('bottomSheet'),
  onPressed:(){
  	Get.bottomSheet(
      Container(
      	height:150,
        color:Colors.white,
        child:ListView(
        	children:[
          	ListTitle(
            	title:Text('修改密码')
              leading:Icon(Icons.add)//左边的图标
              trailing:Icon(Icons.add)//右边的图标
            ),
            ListTitle(
            	title:Text('注销')
            )
          ]
        )
      )
      enableDrag:false// 禁止拖拽改变大小
      isDismissible:false//点击空白处diglog不关闭
      
    );
  }
)

GET路由

如果你想免上下文(context)使用路由/snackbars/dialogs/bottomsheets,GetX对你来说也是极好的,来吧展示:

在你的MaterialApp前加上 "Get",把它变成GetMaterialApp。

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

导航到新页面

Get.to(NextScreen());

Get.to(NextScreen(),
       transition:native,//动画
       duration:Duration(milliseconds:1000),//延时
  		 arguments:{'name':'jack','age':'20'},//传参
       )


//接收
Get.arguments['name']
Get.arguments['age']  

用别名导航到新页面。

Get.toNamed('/details');

//定义路由
  void main() {
  runApp(
    GetMaterialApp(
      initialRoute: '/',
      defaultTransition:Transition.zoom 
      getPages: [
        GetPage(name: '/', page: () => MyHomePage()),
        GetPage(name: '/second', page: () => Second()),
        GetPage(
          name: '/third',
          page: () => Third(),
          transition: Transition.zoom  //动画
        ),
      ],
      routingCallback: (routing) { //中间件 可用作路由拦截
      	if(routing.current == '/second')
        	{
      			openAds();
        	}
  			}
    	)
  );
}

//动态网页链接
Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");

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


//NamedParameters。
void main() {
  runApp(
    GetMaterialApp(
      initialRoute: '/',
      getPages: [
        GetPage(
        name: '/profile/',
        page: () => MyProfile(),
      ),
       //你可以为有参数的路由定义一个不同的页面,也可以为没有参数的路由定义一个不同的页面,但是你必须在不接收参数的路由上使用斜杠"/",就像上面说的那样。
       GetPage(
        name: '/profile/:user',
        page: () => UserProfile(),
      ),
     ],
    )
  );
}

//发送别名路由数据
Get.toNamed("/second/34954");

//在第二个页面上,通过参数获取数据
print(Get.parameters['user']);
// out: 34954

//发送多个参数
Get.toNamed("/profile/34954?flag=true");
//参数获取数据
print(Get.parameters['user']);
print(Get.parameters['flag']);

要关闭snackbars, dialogs, bottomsheets或任何你通常会用Navigator.pop(context)关闭的东西。

Get.back();

进入下一个页面,但没有返回上一个页面的选项(用于闪屏页,登录页面等)。

Get.off(NextScreen());

进入下一个页面并取消之前的所有路由(在购物车、投票和测试中很有用)。

Get.off(NextScreen());

状态管理器

// controller
final count1 = 0.obs;
final count2 = 0.obs;
int get sum => count1.value + count2.value;
// 视图
GetX<Controller>(
  builder: (controller) {
    print("count 1 rebuild");
    return Text('${controller.count1.value}');
  },
),
GetX<Controller>(
  builder: (controller) {
    print("count 2 rebuild");
    return Text('${controller.count2.value}');
  },
),
GetX<Controller>(
  builder: (controller) {
    print("count 3 rebuild");
    return Text('${controller.sum}');
  },
),
Obx(() => Text("Clicks: ${c.count}"))

如果我们把count1.value++递增,就会打印出来:

  • count 1 rebuild

  • count 3 rebuild

如果我们改变count2.value++,就会打印出来。

  • count 2 rebuild

  • count 3 rebuild

类实例化观察者

//可以将你的类值转换为 obs
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;
}

// controller
final user = User().obs;
//当你需要更新user变量时。
user.update( (user) { // 这个参数是你要更新的类本身。
    user.name = 'Jonny';
    user.age = 18;
});
// 更新user变量的另一种方式。
user(User(name: 'João', age: 35));

// view
Obx(
  ()=> Text("Name ${user.value.name}: Age: ${user.value.age}")
);
// 你也可以不使用.value来访问模型值。
user().name; // 注意是user变量,而不是类变量(首字母是小写的)。

Workers

//控制器初始化
  // controller
class Controller extends GetxController{
	final count1 = 0.obs;
	final count2 = 0.obs;
	int get sum => count1.value + count2.value;
  
  void onInit(){
  	super.onInit();
    
    ever(count1,(callback){
      //每次count1变化时触发。例如处理购物车价格
    })
      
    once(count1, (callback) {
      //只有在变量count1第一次被改变时才会被调用
      //例如用户登录信息
      print("count1 was changed once")); 
    }) 
    
    debounce(count1, (callback) {
       //防抖 - 每当用户停止输入1秒时调用,例如搜索
      print("count1 debouce")); 
      time: Duration(seconds: 1));  
    }) 
      
    interval(count1, (callback) {
       //节流 - 每隔一秒再调用,例如滑动再刷新
      print("count1 interval")); 
      time: Duration(seconds: 1));  
    })   
	
      
  }
 
}

简单状态处理器

controller

class Controller extends GetxController{
	var count1 = 0;
  final count1 = 0.obsl
  int get sum => count1.value + count2.value;
  
   static Controller get to => Get.find(); // 注册到to对象
  
  void increment(){
    count1++;
    update();
  }
}

View

FloatingActionButton(
  onPressed: () {
    Controller.to.increment(),
  } // 
  child: Text("${Controller.to.counter}"),
),

//或
GetBuilder<Controller>(
  init: Controller(),
  builder: (value) => Text(
    '${value.counter}', //here
  ),
),

使用ID更新

//controller
class Controller extends GetxController{
	var count1 = 0;
  final count1 = 0.obsl
  int get sum => count1.value + count2.value;
  
   static Controller get to => Get.find(); // 注册到to对象
  
  void increment(){
    count1++;
    update(['text1']);
  }
}



//view
GetBuilder<Controller>(
  init: Controller(),
  id:'text1',
  builder: (value) => Text(
    '${value.counter}', //here
  ),
),

依赖管理

Get.put()

Get.put<SomeClass>(SomeClass());
Get.put<LoginController>(LoginController(), permanent: true);
Get.put<ListItemController>(ListItemController, tag: "some unique string");


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,
)

Get.lazyPut

可以懒加载一个依赖,这样它只有在使用时才会被实例化。这对于计算代价高的类来说非常有用,或者如果你想在一个地方实例化几个类(比如在Bindings类中),而且你知道你不会在那个时候使用这个类。

///只有当第一次使用Get.find<ApiMock>时,ApiMock才会被调用。
Get.lazyPut<ApiMock>(() => ApiMock());

Get.lazyPut<FirebaseAuth>(
  () {
    // ... some logic if needed
    return FirebaseAuth();
  },
  tag: Math.random().toString(),
  fenix: true
)

Get.lazyPut<Controller>( () => Controller() )

Get.putAsync

Get.putAsync<SharedPreferences>(() async {
  final prefs = await SharedPreferences.getInstance();
  await prefs.setInt('counter', 12345);
  return prefs;
});

Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )
  
 //参数 
 Get.putAsync<S>(

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

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

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

Get_Cli

flutter pub global activate get_cli

get create project:getxdemo
  
  
E:\flutter\getx>get create project:getxdemo
  1) Flutter Project
  2) Get Server
1

? What is your company's domain?  Example: com.yourcompany  com.yourcompany

what language do you want to use on ios?

  1) Swift
  2) Objective-C
1

what language do you want to use on android?

  1) Kotlin
  2) Java
1

Do you want to use null safe?

  1) Yes!
  2) No
1

do you want to use some linter?

  1) no
  2) Pedantic [Deprecated]
  3) Effective Dart [Deprecated]
  4) Dart Recommended
4

Running `flutter create E:\flutter\getx\getxdemo` …

$ flutter create --no-pub -i swift -a kotlin --org com.yourcompany E:\flutter\getx\getxdemo
Creating project ....
  lib\main.dart (created)
  pubspec.yaml (created)
  README.md (created)
  test\widget_test.dart (created)
  .gitignore (created)
  .idea\libraries\Dart_SDK.xml (created)
  .idea\libraries\KotlinJavaRuntime.xml (created)
  .idea\modules.xml (created)
  .idea\runConfigurations\main_dart.xml (created)
  .idea\workspace.xml (created)
  .metadata (created)
  analysis_options.yaml (created)
  android\app\build.gradle (created)
  android\app\src\main\kotlin\com\yourcompany\getxdemo\MainActivity.kt (created)
  android\build.gradle (created)
  android\getxdemo_android.iml (created)
  android\.gitignore (created)
  android\app\src\debug\AndroidManifest.xml (created)
  android\app\src\main\AndroidManifest.xml (created)
  android\app\src\main\res\drawable\launch_background.xml (created)
  android\app\src\main\res\drawable-v21\launch_background.xml (created)
  android\app\src\main\res\mipmap-hdpi\ic_launcher.png (created)
  android\app\src\main\res\mipmap-mdpi\ic_launcher.png (created)
  android\app\src\main\res\mipmap-xhdpi\ic_launcher.png (created)
  android\app\src\main\res\mipmap-xxhdpi\ic_launcher.png (created)
  android\app\src\main\res\mipmap-xxxhdpi\ic_launcher.png (created)
  android\app\src\main\res\values\styles.xml (created)
  android\app\src\main\res\values-night\styles.xml (created)
  android\app\src\profile\AndroidManifest.xml (created)
  android\gradle\wrapper\gradle-wrapper.properties (created)
  android\gradle.properties (created)
  android\settings.gradle (created)
  ios\Runner\AppDelegate.swift (created)
  ios\Runner\Runner-Bridging-Header.h (created)
  ios\Runner.xcodeproj\project.pbxproj (created)
  ios\Runner.xcodeproj\xcshareddata\xcschemes\Runner.xcscheme (created)
  ios\.gitignore (created)
  ios\Flutter\AppFrameworkInfo.plist (created)
  ios\Flutter\Debug.xcconfig (created)
  ios\Flutter\Release.xcconfig (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Contents.json (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-1024x1024@1x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@1x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@2x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-20x20@3x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@1x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@2x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-29x29@3x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@1x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@2x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-40x40@3x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-60x60@2x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-60x60@3x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-76x76@1x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-76x76@2x.png (created)
  ios\Runner\Assets.xcassets\AppIcon.appiconset\Icon-App-83.5x83.5@2x.png (created)
  ios\Runner\Assets.xcassets\LaunchImage.imageset\Contents.json (created)
  ios\Runner\Assets.xcassets\LaunchImage.imageset\LaunchImage.png (created)
  ios\Runner\Assets.xcassets\LaunchImage.imageset\LaunchImage@2x.png (created)
  ios\Runner\Assets.xcassets\LaunchImage.imageset\LaunchImage@3x.png (created)
  ios\Runner\Assets.xcassets\LaunchImage.imageset\README.md (created)
  ios\Runner\Base.lproj\LaunchScreen.storyboard (created)
  ios\Runner\Base.lproj\Main.storyboard (created)
  ios\Runner\Info.plist (created)
  ios\Runner.xcodeproj\project.xcworkspace\contents.xcworkspacedata (created)
  ios\Runner.xcodeproj\project.xcworkspace\xcshareddata\IDEWorkspaceChecks.plist (created)
  ios\Runner.xcodeproj\project.xcworkspace\xcshareddata\WorkspaceSettings.xcsettings (created)
  ios\Runner.xcworkspace\contents.xcworkspacedata (created)
  ios\Runner.xcworkspace\xcshareddata\IDEWorkspaceChecks.plist (created)
  ios\Runner.xcworkspace\xcshareddata\WorkspaceSettings.xcsettings (created)
  getxdemo.iml (created)
  web\favicon.png (created)
  web\icons\Icon-192.png (created)
  web\icons\Icon-512.png (created)
  web\icons\Icon-maskable-192.png (created)
  web\icons\Icon-maskable-512.png (created)
  web\index.html (created)
  web\manifest.json (created)
Wrote 81 files.

All done!
In order to run your application, type:

  $ cd .
  $ flutter run

Your application code is in .\lib\main.dart.


Running `flutter pub get` …

$ flutter pub get
Running "flutter pub get" in getxdemo...
Got socket error trying to find package cupertino_icons at https://pub.dartlang.org.
pub get failed (server unavailable) -- attempting retry 1 in 1 second...
Got socket error trying to find package flutter_lints at https://pub.dartlang.org.
pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...
Running "flutter pub get" in getxdemo...                          612.9s
$ dart migrate --apply-changes --skip-import-check
Migrating E:\flutter\getx\getxdemo

See https://dart.dev/go/null-safety-migration for a migration guide.

Analyzing project...
All sources appear to be already migrated.  Nothing to do.
✖  + HandshakeException: Connection terminated during handshake

✓  File: analysis_options.yaml created successfully at path: analysis_options.yaml
  1) GetX Pattern (by Kauê)
  2) CLEAN (by Arktekko)
1

Your lib folder is not empty. Are you sure you want to overwrite your application?
 WARNING: This action is irreversible

  1) Yes!
  2) No
1
✖  + HandshakeException: Connection terminated during handshake

✓  File: main.dart created successfully at path: lib\\main.dart
✓  File: home_controller.dart created successfully at path: ./lib\app\modules\home\\controllers\\home_controller.dart
✓  File: home_view.dart created successfully at path: ./lib\app\modules\home\\views\\home_view.dart
✓  File: home_binding.dart created successfully at path: ./lib\app\modules\home\\bindings\\home_binding.dart
✓  File: app_routes.dart created successfully at path: lib\\app\\routes\\app_routes.dart
✖  + Package: get is not installed in this application


Time: 6636020 Milliseconds

No active package get_cli.

创建一个页面

get create page:login

更新数据

//view

GetBuilder<LoginController>(builder:(login){
	id:'userName'
	return Text('当前登录用户:${login.name}')
})
ElevatedButton(
	onPressed:(){
  	controller.changeUser();
  },
  child:Text('click')
)

//Controller
class HomeController extends GetxController {
  //TODO: Implement HomeController
  
  var name = 'miles'

  final count = 0.obs;
  @override
  void onInit() {
    super.onInit();
  }

  @override
  void onReady() {
    super.onReady();
  }
  
  changeUser(){
    name = 'admin';
    update('userName')
  }

  @override
  void onClose() {}
  void increment() => count.value++;
}

代码世界的构建师,现实生活的悠游者。