Getx连接地址

状态管理

通俗的讲: 当我们想在多个页面(组件Widget) 之间共享状态 (数据),或者一个页面(组件Widget)中的多个子组件之间共享状态(数据),这个时候我们就可以用Futter中的状态管理来管理统一的状态 (数据),实现不同组件之间的传值和数据共享。
现在Flutter状态管理方案很多,redux、bloc、state、 provider、Getx。provider是官方提供的状态管理解决方案,主要功能就是状态管理。Getx是第三方的状态管理插件不仅具有状态管理的功能,还具有路由管理主题管理国际化多语言管理Obx局部更新网络请求数据验证等功能,相比其他状态管理插件Getx 简单、功能强大并且高性能。

Get有两个不同的状态管理器: 简单的状态管理器 (GetBuilder) 和响应式状态管理器 (Getx)。

响应式状态管理器

  1. 不需要创建StreamControllers.
  2. 不需要为每个变品创建一个StreamBuilder
  3. 不需要为每个状态创建一个类。
  4. 不需要为一个初始值创建一个get。

让我们想象一下,你有一个名称变量,并且希望每次你改变它时,所有使用它的小组件都会自动刷新。

1
var name ="Jonatas Borges';

要想让它变得可观察,你只需要在它的末尾加上”.obs”

1
var name m Jonatas Borges'.obs;

而在UI中,当你想显示该值并在值变化时更新页面,只需这样做!

1
Obx(() => Text("s(controller.name]"));

定义响应式变量几种方法

  1. 第一种使用 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);
  2. 第二种使用 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>();
  3. 第三种使用 .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;
})
// or
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
///每次~count1变化时调用。
ever(count, (_) => print("$_ has been changed"));
///只有在变量s 第一次被改变时才会被训用。
once(count,(_) => print("$_ was changed once"));
///防DDos - 每当用户停止输入1秒时调用,例如。
debounce(count, (_) => print("debouce$_"), time: Duration(seconds: 1));
///忽略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++;
// id: '112412',
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{

// final int count = 0.obs; // 错误写法
// count 该 count 类型为 int 包装类,在获取值的时候 需要通过 count.value 形式来获取
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';
// 之前定义的 Controller 类
import '../controller/controller.dart';

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

@override
State<GetxStatusManagerDemo> createState() => _GetxStatusManagerDemoState();
}

class _GetxStatusManagerDemoState extends State<GetxStatusManagerDemo> {

// 获取 getx 中定义的 container
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中的方法重新赋值
controller.initail();
}, icon: const Icon(Icons.refresh), label: const Text('刷新'))
],
)
),
),
floatingActionButton: FloatingActionButton(onPressed: (){
// 调用 controller 中的 increment 方法
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
flutter pub add get

引入小部件

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
// Snackbar
ElevatedButton(
onPressed: () {
Get.snackbar(
'提示',
'Snackbar',
overlayColor: Colors.blue,
// 开启手势关闭
isDismissible: true,
// 关闭手势 向上滑动关闭
dismissDirection: DismissDirection.up,
// 左侧 Icon
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
// bottomSheet
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();
// Get.changeThemeMode(ThemeMode.light);
},
leading: Icon(Icons.sunny),
title: Text('白天模式', style: TextStyle(color: Get.isDarkMode ? Colors.white :Colors.black),),
),
ListTile(
onTap: (){
Get.changeTheme(ThemeData.dark());
Get.back();
// Get.changeThemeMode(ThemeMode.dark);
},
leading: Icon(Icons.money_off),
title: Text('黑夜模式', style: TextStyle(color: Get.isDarkMode ? Colors.white :Colors.black),),
)
],
),
),
),
// 设置顶部圆角
/* shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25))
) */
// 取消点击遮罩关闭
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
}
);

接受参数

1
Get.arguments

命名路由

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), //游戏中心页面的列表页

};
// 配置 onGenerateRoute
var onGenerateRoute = (RouteSettings settings) {
// '/shopping':(context) => MyShoppingPage(),
final String? routeName = settings.name; // /shopping
final Function? routeFunction = routes[routeName]; // MyShoppingPage()
// 找到对应的路由部件进行跳转
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(name: '/viewDetail', page: () => ViewDetailPage()),
];

GetPage 可单独 配置 transitiondefaultTransition 动画 可以设置默认动画,统一设置路由跳转动画效果!

注意: 路由传参 只需要在跳转路由的地方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';

// GetMiddleware 中间件
class ShoppingMiddleware extends GetMiddleware{

@override
RouteSettings? redirect(String? route) {
print(route);
// 为空 表示不做任何操作
// 跳转到 shopping route 时重定向到 /gridViewList
return const RouteSettings(name: "/gridViewList", arguments: {});
// return null;
}
}
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,
// 配置 shopping 路由鉴权
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(
// 关闭右上角 debugger 标识
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
open ~/.bash_profile
1
2
#getX
export PATH="$PATH":"$HOME/.pub-cache/bin"

查看是否安装成功

1
get --version

创建项目

1
get create project:"my cool project"

常用命令

在现有项目上生成所选结构

1
get init

创建页面

要创建页面:(页面具有控制器、视图和绑定)

1
get create page:home

创建屏幕

创建屏幕(屏幕有控制器、视图和绑定)注意:您可以使用任何名称,例如:“获取屏幕页面:登录”

1
get create screen

添加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

指定版本安装包

1
get install path:1.6.4

更新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
  1. 选择flutter项目,之所以有两个选项,是因为框架,不仅支持 flutter 也支持server 端!
  2. 指定公司域名com.example
    android中是package名!
    ios中是bundleId!注意: 在实际项目中,这个地方要一开始就配置好,后期配置的话,不太便捷!
  3. 选择androidios 语言
    在这我选择了第一项 swiftkotlin
    后面就是 是否需要 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();
// await run('dart migrate --apply-changes --skip-import-check',
// verbose: true);
}

重新激活`get_cli`

1
2
flutter pub global deactivate get_cli
flutter pub global activate get_cli