Getx连接地址 引用站外地址
Getx下载地址
https://pub.dev/packages/get
引用站外地址
Getx中文文档地址
https://github.com/jonataslaw/getx/blob/master/README.zh-cn.md
引用站外地址
掘金 Getx 路由管理
https://juejin.cn/post/7227486312340095033
引用站外地址
Getx b站视频教程
https://www.bilibili.com/video/BV1fg411V7eG/?spm_id_from=333.337.search-card.all.click&vd_source=eecc2c8229facae905b6daed1650b44b
状态管理 通俗的讲: 当我们想在多个页面(组件Widget) 之间共享状态 (数据),或者一个页面(组件Widget)中的多个子组件之间共享状态(数据),这个时候我们就可以用Futter中的状态管理来管理统一的状态 (数据),实现不同组件之间的传值和数据共享。 现在Flutter的状态管理方案很多,redux、bloc、state、 provider、Getx。provider是官方提供的状态管理解决方案,主要功能就是状态管理。Getx是第三方的状态管理插件不仅具有状态管理的功能,还具有路由管理、主题管理、国际化多语言管理、Obx局部更新、网络请求、数据验证等功能,相比其他状态管理插件Getx 简单、功能强大并且高性能。
Get有两个不同的状态管理器: 简单的状态管理器 (GetBuilder) 和响应式状态管理器 (Getx)。
响应式状态管理器 不需要创建StreamControllers. 不需要为每个变品创建一个StreamBuilder。 不需要为每个状态创建一个类。 不需要为一个初始值创建一个get。 让我们想象一下,你有一个名称变量,并且希望每次你改变它时,所有使用它的小组件都会自动刷新。
1 var name ="Jonatas Borges';
要想让它变得可观察,你只需要在它的末尾加上”.obs”
1 var name m Jonatas Borges'.obs;
而在UI中,当你想显示该值并在值变化时更新页面,只需这样做!
1 Obx(() => Text("s(controller.name]" ));
定义响应式变量几种方法 第一种使用 Rx(Type)1 2 3 4 5 6 7 final name = RxString('' );final isLogged = RxBool(false );final count = RxInt(e);final balance = RxDouble(e.e);final items = RxList<String >([]);final myMap = RxMap<string, int >((3 );
第二种使用 Rx, 定义泛型Rx<Type>1 2 3 4 5 6 7 8 9 final name = Rx<String >('' );final isLogged = Rx<Bool>(false );final count m Rx<Int>(e);final balance = Rx<Double>(0. @);final number = Rx<Num>(e)final items = Rx<List <String >>([]);final myMap = Rx<Map <string,int >>({});final user = Rx<User>();
第三种使用 .obs作为value的属性!1 2 3 4 5 6 7 8 9 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;
有一个反应的状态,很容易。
我们知道,Dart 现在正朝着 nullsafety 的方向发展。为了做准备,从现在开始,你应该总是用一个初始值来开始你的 Rx 变量用GetX将一个变量转化为一个_observable_+ initial value 是最简单,也是最实用的方法你只需在变量的末尾添加一个".obs",即可把它变成可观察的变量,然后它的 value 就是 初始值)。
观察类 Model
Model 1 2 3 4 5 class User { User({this .name = '' , this .age = 0 }); String name; int age; }
Controller
Controller 1 2 3 4 5 6 7 final user = new User().obs;user.update((user) => { user.name = 'jonny' ; user.age = 18 ; }) user(User({name: 'jonny' , age: 18 }))
View
1 Obx(() => Text('${user.value.name} ${user.value.age} ' ))
观察List Workers 监听值变化 Workers将协助你在事件发生时触发特定的回调。
1 2 3 4 5 6 7 8 ever(count, (_) => print ("$_ has been changed" )); once(count,(_) => print ("$_ was changed once" )); debounce(count, (_) => print ("debouce$_ " ), time: Duration (seconds: 1 )); interval(count, (_) => print ("interval $_ " ), time: Duration (seconds: 1 ));
GetBuilderId 当一个Controller中的某个变量被多个地方所共享时,如何控制只需要当前界面变量所更新呢?
1 2 3 4 5 GetX<Controller>( id: '112412' , builder: (controller) { return Text('${controller.count.value} ' ); },),
在Controller 中 更新的方法当中 配置 需要某个地方更新的逻辑!
1 2 3 4 5 increment() { count++; update(['112412' ]); }
Demo 创建Controller Controller.dart 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import 'package:get/get.dart' ;class Controller extends GetxController { var count = 0. obs; initail() { count.value = 0 ; } increment() => count++; }
在页面中使用 StatefulWidget 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import 'package:flutter/material.dart' ;import 'package:get/get.dart' ;import '../controller/controller.dart' ;class GetxStatusManagerDemo extends StatefulWidget { const GetxStatusManagerDemo({super .key}); @override State<GetxStatusManagerDemo> createState() => _GetxStatusManagerDemoState(); } class _GetxStatusManagerDemoState extends State <GetxStatusManagerDemo > { final controller = Get.put(Controller()); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Container( width: double .infinity, padding: const EdgeInsets.all(15 ), child: Column( children: [ GetX<Controller>(builder: (controller) { return Text('${controller.count.value} ' ); },), ElevatedButton.icon(onPressed: (){ controller.initail(); }, icon: const Icon(Icons.refresh), label: const Text('刷新' )) ], ) ), ), floatingActionButton: FloatingActionButton(onPressed: (){ controller.increment(); }, child: const Icon(Icons.add),), ); } }
GetX<Controller>当状态发生改变后,只会影响局部刷新!
注意: final controller = Get.put(Controller()); 在 StatelessWidget 中 状态是无法随时更新的!
StatelessWidget 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import 'package:flutter/material.dart' ;import 'package:get/get.dart' ;import '../controller/controller.dart' ;final controller = Get.put(Controller());class GetxRoutePage extends StatelessWidget { const GetxRoutePage({super .key}); @override Widget build(BuildContext context) { return Center( child: Container( width: double .infinity, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton(onPressed: (){ Get.toNamed("/gridViewList" ); }, child: const Text("gridViewList" )), ElevatedButton(onPressed: (){ Get.toNamed("/shopping" ); }, child: const Text("shopping" )), Text('${controller.count.value} ' ), ElevatedButton.icon(onPressed: (){ controller.initail(); }, icon: const Icon(Icons.refresh), label: const Text('刷新' )) ] ), ), ); } }
安装 Getx 引入小部件
1 import 'package:get/get.dart' ;
Getx中的小部件 Dialog 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ElevatedButton( onPressed: () { Get.defaultDialog( title: '提示信息!' , titlePadding: const EdgeInsets.only(left: 0 ), middleText: '确定要继续吗?' , confirm: ElevatedButton( onPressed: (){ print ('confirm ~' ); Get.back(); }, child: const Text('确定' ) ), cancel: TextButton(onPressed: (){ print ('cancel ~' ); Get.back(); }, child: const Text('取消' )) ); }, child: const Text('Open Getx Dialog!' ) ),
Snackbar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ElevatedButton( onPressed: () { Get.snackbar( '提示' , 'Snackbar' , overlayColor: Colors.blue, isDismissible: true , dismissDirection: DismissDirection.up, icon: const Icon(Icons.snowing), duration: const Duration (seconds: 10000 ), backgroundColor: Colors.grey.withOpacity(0.6 ) ); }, child: const Text('Open Snackbar!' ), ),
BottomSheet 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 ElevatedButton(onPressed: () { Get.bottomSheet( Center( child: Container( width: double .infinity, padding: const EdgeInsets.all(15 ), decoration: BoxDecoration( color: Get.isDarkMode ? Colors.black26 :Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(25 ), topRight: Radius.circular(25 )) ), child: Column( children: [ ListTile( onTap: (){ print ('白天模式!' ); Get.changeTheme(ThemeData.light()); Get.back(); }, leading: Icon(Icons.sunny), title: Text('白天模式' , style: TextStyle(color: Get.isDarkMode ? Colors.white :Colors.black),), ), ListTile( onTap: (){ Get.changeTheme(ThemeData.dark()); Get.back(); }, leading: Icon(Icons.money_off), title: Text('黑夜模式' , style: TextStyle(color: Get.isDarkMode ? Colors.white :Colors.black),), ) ], ), ), ), isDismissible: false , ); }, child: const Text('Open BottomSheet!' )),
切换主题 1 Get.changeTheme(ThemeData.light());
使用 Get.isDarkModel 可以判断当前模式是否为 暗黑模式!
Getx路由管理 Getx为我们封装了Navigation,无需 context 可进行跳转,使用Getx 进行路由跳转非常的简单只需要调用 Get.to()即可进行路由跳转,Getx 路由跳转简化了跳转动画设置、动画时长定义、动画曲线设置。
Get.to()跳转到普通路由 Get.to(const widget())
Get.toNamed()跳转到命名路由 Get.toNamed('/home') 带参 Get.toNamed('/home', arguments: { id: '588231623782'})
Get.back()返回上一个路由
返回到上一个页面(对应于Get.to放到到路由页面跳转有效,off方法页面跳转无效)
如果需要携带数据返回可加result参数:Get.back(result)
然后上一个页面接收返回的数据:var result = await Get.to(page);
Get.offAll()返回到 root(根) 路由
Get.off()页面跳转,参数为 页面小部件 widget Get.off(const widget()) 跳转到的路由界面没有返回按钮, 适用于 第一次打开页面到首页…!
Get.offNamed()Get.off() 和 Get.offNamed() 这两个效果是一样的。表示跳到下一个页面,会关闭上一个页面。
Get.offAllNamed()Get.offAll() 和 Get.offAllNamed() 跳转到下个页面,便关闭其他Route,跳转到的页面不会有返回按钮!
Get.offUntil()对应的原生路由 Navigation.pushAndRemoveUntil()
在使用上述方式跳转时,会按次序移除其他的路由,直到遇到被标记的路由(predicate函数返回了true)时停止。若 没有标记的路由,则移除全部。当路由栈中存在重复的标记路由时,默认移除到最近的一个停止。
1 Get.offUntil(GetPageRoute(page: () => SecondPage()),(route) => (route as GetPageRoute).routeName == null );
Get.offAndToNamed()对应的原生路由是 Navigation.popAndPushNamed() pushReplacement pushReplacementNamed
表示跳到的下一个页面会替换上一个页面。
路由传参 arguments 带参 以前写法
1 2 3 4 5 6 7 8 Navigator.pushNamed( context, '/viewDetail' , arguments: { "detail" : resData[index], "photoList" : resData, "initalIndex" : index } );
Get写法
1 2 3 4 5 6 7 8 Get.toNamed( "/viewDetail" , arguments: { "detail" : resData[index], "photoList" : resData, "initalIndex" : index } );
接受参数
命名路由Get.toNamed("/second")可以直接使用arguments传参,也可以直接在路由别名后面跟参数,类似于 Url get 传参的方式:
传参方式
1 Get.toNamed("/second?name=river" )
接受参数
1 print (Get.parameters['name' ]);
如果使用这种命名路由的话,需要声明一个路由注册。具体声明如下代码所示: 1 2 3 4 5 6 class Routers { static const second = '/second' ; static List <GetPage> getPages = [ GetPage(name: second, page: () => SecondPage()) ]; }
结合 onGenerateRoute 该方式不支持 defaultTransition 路由动画配置
routes.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import 'package:flutter/material.dart' ;import '../pages/routePage/shopping.dart' ;import '../pages/routePage/individualCenter.dart' ;import '../animated/hero/gridViewList.dart' ;import '../animated/hero/viewDetail.dart' ;Map routes = { '/shopping' :(context) => MyShoppingPage(), '/individualCenter' :(context, { arguments }) => MyIndividualCenterPage(arguments: arguments), '/gridViewList' : (context) => const MyGridViewListPage(), '/viewDetail' : (context, { arguments }) => ViewDetailPage(arguments: arguments), }; var onGenerateRoute = (RouteSettings settings) { final String? routeName = settings.name; final Function? routeFunction = routes[routeName]; if ( routeFunction != null ) { if ( settings.arguments != null ) { return MaterialPageRoute(builder: (context) => routeFunction( context, arguments: settings.arguments )); } Route route = MaterialPageRoute(builder: (context) => routeFunction( context )); return route; } };
结合 getPages 该方式支持 defaultTransition 路由动画配置
getxRoutes.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import 'package:flutter/material.dart' ;import 'package:get/get.dart' ;import '../pages/routePage/shopping.dart' ;import '../pages/routePage/individualCenter.dart' ;import '../animated/hero/gridViewList.dart' ;import '../animated/hero/viewDetail.dart' ;List <GetPage<dynamic >> getPages = [ GetPage(name: '/shopping' , page: () => MyShoppingPage(), transition: Transition.cupertino), GetPage(name: '/gridViewList' , page: () => const MyGridViewListPage()), ];
GetPage 可单独 配置 transition,defaultTransition 动画 可以设置默认动画,统一设置路由跳转动画效果!
注意: 路由传参 只需要在跳转路由的地方Get.toNamed('/', arguments: { id: '578137873892'}) 即刻,不需要在 GetPage 小部件里配置arguments, 在 接受 参数的小部件里,通过 Get.arguments 来接受!
未知路由 创建 UnknownRoutePage.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class UnknownRoutePage extends StatelessWidget { const UnknownRoutePage({Key? key}) : super (key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("路由没有找到" ), ), body: ListTile( title: Text("返回首页" ), subtitle: Text('Get.offAllNamed(AppRoutes.Home)' ), onTap: () => Get.offAllNamed(AppRoutes.Home), ), ); } }
配置GetPage路由
1 2 3 GetMaterialApp( unknownRoute: GetPage(name: '/notfound' , page: () => UnknownRoutePage()), )
路由拦截 routingCallback当触发路由事件的时候,会回调GetMaterialApp里的一个回调方法routingCallback
1 2 3 4 5 6 7 8 9 10 11 12 13 GetMaterialApp( unknownRoute: GetPage(name: '/notfound' , page: () => UnknownRoutePage()), routingCallback: (routing) { if (routing?.current == '/second' ){ } }, initialRoute: '/' , getPages: [ GetPage(name: '/first' , page: ()=>First()), GetPage(name: '/second' , page: ()=>Second()) ], )
如果你没有使用 GetMaterialApp ,你可以使用手动API来附加 Middleware 观察器。
middleware新建middleware
lib/middleware/shoppingMiddleware.dart 继承 GetMiddleware 并实现 RouteSettings 方法! return null 则代表不做任何操作!
Redirect
当被调用路由的页面被搜索时,这个函数将被调用。它将Routesettings作为重定向的结果。或者给它null,就没有重定向了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import 'package:flutter/material.dart' ;import 'package:get/get.dart' ;class ShoppingMiddleware extends GetMiddleware { @override RouteSettings? redirect(String? route) { print (route); return const RouteSettings(name: "/gridViewList" , arguments: {}); } }
1 2 3 4 RouteSettings redirect(string route) { final authService = Get.find<AuthService>(); return authService.authed.value ? null : RouteSettings(name: '/login' ); }
单独配置,在 GetPage 中 引入 middlewares: [ ShoppingMiddleware() ]
1 2 3 4 5 6 7 GetPage( name: '/shopping' , page: () => MyShoppingPage(), transition: Transition.cupertino, middlewares: [ ShoppingMiddleware() ] ),
onPageCalled
在调用页面时,创建任何东西之前,这个函数会先被调用。您可以使用它来更改页面的某些内容或给它一个新页面。
1 2 3 4 GetPage onPageCalled(GetPage page) ( final authService = Get.find<AuthService>(); return page.copywith(title: "welcome $(authService.UserName]'); }
OnBindingsStart
这个函数将在绑定初始化之前被调用。 在这里,您可以更改此页面的绑定!
1 2 3 4 5 6 7 List <Bindings> onBindingsStart(List <Bindings> bindings){ final authService = Get.find<AuthService>( ); if (authservice.isAdmin) [ bindings.add(AdminBinding()); ] return bindings; }
OnPageBuildStart
这个函数将在绑定初始化之后被调用。 在这里,您可以在创建绑定之后和创建页面widget之前执行一些操作.
1 2 3 4 GetPageBuilder onPageBuildstart(GetPageBuilder page) { print ( 'bindings are ready' ); return page; }
OnPageBuilt 这个函数将在GetPage.page调角后被调用,并给出函数的结果,并获取将要显示的widget。
OnPageDispose 这个函数将在处理完页面的所有相关对象(Controllers, views,...)之后被调用
设置优先级
1 2 3 4 5 6 final middlewares =[ GetMiddleware(priority: 2 ), GetMiddleware(priority: 5 ), GetMiddleware(priority: 4 ), GetMiddleware(priority: -8 ) ];
这些中间件会按这个顺序执行 -8 => 2 => 4 => 5
路由封装 创建AppRoutes
lib/routes/app_routes.dart
AppRoutes 1 2 3 4 5 6 7 8 part of 'app_pages.dart' ;abstract class AppRoutes { static const Home = '/home' ; static const List = '/list' ; static const Detail = '/detail' ; }
创建AppPages
lib/routes/app_pages.dart
AppRoutes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import 'package:get/get.dart' ;part 'app_routes.dart' ;class AppPages { static const INITIAL = AppRoutes.Home; static final routes = [ GetPage( name: AppRoutes.Home, page: () => HomeView(), children: [ GetPage( name: AppRoutes.List , page: () => ListView(), children: [ GetPage( name: AppRoutes.Detail, page: () => DetailView(), ), ], ), ], ), ]; }
main.dart
main 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Future<void > main() async { runApp(MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super (key: key); @override Widget build(BuildContext context) { return GetMaterialApp( debugShowCheckedModeBanner: false , initialRoute: AppPages.INITIAL, getPages: AppPages.routes, ); } }
导航操作 命名、视图对象
导航操作 命名、视图对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ListTile( title: Text("导航-命名路由 home > list" ), subtitle: Text('Get.toNamed("/home/list")' ), onTap: () => Get.toNamed("/home/list" ), ), ListTile( title: Text("导航-命名路由 home > list > detail" ), subtitle: Text('Get.toNamed("/home/list/detail")' ), onTap: () => Get.toNamed("/home/list/detail" ), ), ListTile( title: Text("导航-类对象" ), subtitle: Text("Get.to(DetailView())" ), onTap: () => Get.to(DetailView()), ),
导航-清除上一个
当前路由替换上一个路由 1 2 3 4 5 6 ListTile( title: Text("导航-当前路由替换上一个路由" ), subtitle: Text("Get.off(DetailView())" ), onTap: () => Get.off(DetailView()), ),
导航-清除所有
清除所有 1 2 3 4 5 6 ListTile( title: Text("导航-清除所有" ), subtitle: Text("Get.offAll(DetailView())" ), onTap: () => Get.offAll(DetailView()), ),
导航-arguments 传值+返回值
导航-arguments 传值+返回值 1 2 3 4 5 6 7 8 9 10 11 ListTile( title: Text("导航-arguments传值+返回值" ), subtitle: Text( 'Get.toNamed("/home/list/detail", arguments: {"id": 999})' ), onTap: () async { var result = await Get.toNamed("/home/list/detail" , arguments: {"id" : 999 }); Get.snackbar("返回值" , "success -> " + result["success" ].toString()); }, ),
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 _buildBackListTileRow(Map? val) { return val == null ? Container() : ListTile( title: Text("传值 id = " + val["id" ].toString()), subtitle: Text('Get.back(result: {"success": true}' ), onTap: () => Get.back(result: {"success" : true }), ); } @override Widget build(BuildContext context) { final details = Get.arguments as Map ; final parameters = Get.parameters; return Scaffold( appBar: AppBar( title: Text("详情页" ), ), body: ListView( children: [ ListTile( title: Text("导航-返回" ), subtitle: Text('Get.back()' ), onTap: () => Get.back(), ), _buildBackListTileRow(details), _buildBackListTileRow(parameters), ], ), ); }
导航-parameters 传值+返回值
导航-parameters 传值+返回值 1 2 3 4 5 6 7 8 9 ListTile( title: Text("导航-parameters传值+返回值" ), subtitle: Text('Get.toNamed("/home/list/detail?id=666")' ), onTap: () async { var result = await Get.toNamed("/home/list/detail?id=666" ); Get.snackbar("返回值" , "success -> " + result["success" ].toString()); }, ),
1 2 3 4 @override Widget build(BuildContext context) { final parameters = Get.parameters;
导航-参数传值+返回值
导航-参数传值+返回值 1 static const Detail_ID = '/detail/:id' ;
1 2 3 4 5 6 ... GetPage( name: AppRoutes.Detail_ID, page: () => DetailView(), ),
1 2 3 4 5 6 7 8 9 ListTile( title: Text("导航-参数传值+返回值" ), subtitle: Text('Get.toNamed("/home/list/detail/777")' ), onTap: () async { var result = await Get.toNamed("/home/list/detail/777" ); Get.snackbar("返回值" , "success -> " + result["success" ].toString()); }, ),
GetCli Get脚手架 类似与 vue-cli 可以快速帮我们生成 规范目录 和 代码!
添加全局get-cli 1 flutter pub global activate get_cli
设置环境变量 打开环境变量文件进行配置
1 2 export PATH="$PATH " :"$HOME /.pub-cache/bin"
查看是否安装成功 创建项目 1 get create project:"my cool project"
常用命令 在现有项目上生成所选结构
创建页面 要创建页面:(页面具有控制器、视图和绑定)
创建屏幕 创建屏幕(屏幕有控制器、视图和绑定)注意:您可以使用任何名称,例如:“获取屏幕页面:登录”
添加controller 要在特定文件夹中创建新控制器,请执行以下操作:注意:您不需要引用文件夹,Getx将自动搜索主文件夹并在那里添加控制器。
1 get create controller:dialogcontroller on home
添加视图 要在特定文件夹中创建新视图,请执行以下操作:注意:您不需要引用文件夹,Getx将自动搜索主文件夹
1 get create view:dialogview on home
在特定文件夹中创建新的提供程序 1 get create provider:user on home
安装包 or 删除包 1 2 get install camera get remove camera
安装 or 删除多个包 1 2 get install http path camera get remove http path camera
指定版本安装包 更新cli 1 2 get update // or `get upgrade`
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 // To install: pub global activate get_cli // (to use this add the following to system PATH: [FlutterSDKInstallDir]\bin\cache\dart-sdk\bin flutter pub global activate get_cli // To create a flutter project in the current directory: // Note: By default it will take the folder's name as project name // You can name the project with `get create project:my_project` // If the name has spaces use `get create project:"my cool project"` get create project // To generate the chosen structure on an existing project: get init // To create a page: // (Pages have controller, view, and binding) // Note: you can use any name, ex: `get create page:login` // Nota: use this option if the chosen structure was Getx_pattern get create page:home // To create a screen // (Screens have controller, view, and binding) // Note: you can use any name, ex: `get screen page:login` // Nota: use this option if the chosen structure was CLEAN (by Arktekko) get create screen:home // To create a new controller in a specific folder: // Note: you don' t need to reference the folder,// Getx will search automatically for the home folder // and add your controller there. get create controller:dialogcontroller on home // To create a new view in a specific folder: // Note: you don't need to reference the folder, // Getx will automatically search for the home folder // and insert your view there. get create view:dialogview on home // To create a new provider in a specific folder: get create provider:user on home // To generate a localization file: // Note: ' assets/locales' directory with your translation files in json format get generate locales assets/locales // To generate a class model: // Note: ' assets/models/user.json' path of your template file in json format // Note: on == folder output file // Getx will automatically search for the home folder // and insert your class model there. get generate model on home with assets/models/user.json //to generate the model without the provider get generate model on home with assets/models/user.json --skipProvider //Note: the URL must return a json format get generate model on home from "https://api.github.com/users/CpdnCristiano" // To install a package in your project (dependencies): get install camera // To install several packages from your project: get install http path camera // To install a package with specific version: get install path:1.6.4 // You can also specify several packages with version numbers // To install a dev package in your project (dependencies_dev): get install flutter_launcher_icons --dev // To remove a package from your project: get remove http // To remove several packages from your project: get remove http path // To update CLI: get update // or `get upgrade` // Shows the current CLI version: get -v // or `get -version` // For help get help
注意: `flutter pub global activate get_cli` 安装后,需要手动配置环境变量! 配置成功后,重新启动`cmd` 输入`get`命令验证是否成功! ### 创建项目1 get create project:my_flutter_getx
选择flutter项目,之所以有两个选项,是因为框架,不仅支持 flutter 也支持server 端! 指定公司域名com.example 在android中是package名! 在ios中是bundleId!注意: 在实际项目中,这个地方要一开始就配置好,后期配置的话,不太便捷! 选择android 和 ios 语言 在这我选择了第一项 swift 和 kotlin 后面就是 是否需要 null safe 是否需要代码检查了安装问题 注意: 如果 安装过程中出现以下异常: 请确认下安装 路径 是否 有空格, 比如文件名 program files 这种一定是安装不成功的!
最后创建成功!
如果出现如下异常
1 + error_unexpected ShellException(dart migrate --apply-changes --skip-import-check, exitCode 64, workingDirectory
原因是migrate是Flutter在2.0时候引入空安全时候使用的一个工具,再3.0之后,就取消了!
而get_cli创建项目的时候执行一句命令就使用了migrate
1 dart migrate --apply-changes --skip-import-check
解决方法就是把执行脚本中的这一条命令注释掉即可,然后重启get_cli工具
window位置
1 C:\Users\xxxxxxxxxxxx\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\get_cli-1.8.4\lib\common\utils\shell\shel.utils.dart
Linux(mac)位置1 $HOME /.pub-cache/hosted/pub.dev/get_cli-1.8.4/lib/common/utils/shell/shel.utils.dart
搜索找到activatedNullSafe() async方法!
注释掉以下代码
1 2 3 4 5 static Future<void > activatedNullSafe() async { await pubGet(); }
重新激活`get_cli`
1 2 flutter pub global deactivate get_cli flutter pub global activate get_cli