一、前言 Flutter开发,就需要对各种状态的管理,就是在请求数据的时候需要实时变化,各种交互变化等,在没有使用GetX之前使用Provider,用Provider的时候觉得真香,挺方便的,需要刷新的时候直接 notifyListeners();
用了GetX之后觉得Provider太繁琐了。这边介绍下GetX的使用以及常用的方法。
二、 GetX GetX 是 Flutter 上的一个轻量且强大的解决方案:高性能的状态管理、智能的依赖注入和便捷的路由管理。 1、相关优势:
代码语言:javascript复制1、轻量,可以模块单独编译,没有用到的功能不会编译进我们的代码
2、刷新简单,
第一种自动刷新 Obx(() => Text())
第二中手动刷新 update()
3、跨页面交互
4、路由管理
getx内部实现了路由管理,这个是非常重要的,这样我们就不需要使用其他第三插件,之前都是使用fluro,现在直接不用了,而且getx的路由管理真的真的非常简单。代码也简洁。
6、国际化、主题的适配
7、获取全局的BuildContext 这个也是比较喜欢的地方,很多时候弹窗或者其他地方,需要拿到上下文,使用getx,直接获取。方便至极
8、依然注入
三、使用 1、第一步 引入get
代码语言:javascript复制dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
get: ^4.1.4
2、第二步 修改入口、配置路由
代码语言:javascript复制@override
Widget build(BuildContext context) {
// 只需要将MaterialApp改成GetMaterialAp
return GetMaterialApp(
title: 'GetX使用',
debugShowCheckedModeBanner: false,
enableLog: true,
initialRoute: '/', //根路由
getPages: Pages.routes, // 配置路由
defaultTransition:
Utils.isIOS() ? Transition.native : Transition.rightToLeft, // 转场动画
themeMode: ThemeMode.system, // 主题
darkTheme: ThemeData.dark(),
theme: ThemeConfig.lightTheme,
home: SplashPage(),
builder: (context, child) {
return Scaffold(
body: GestureDetector(
onTap: () {
hideKeyboard(context);
},
child: FlutterEasyLoading(child: child),
));
},
);
}
3、路由
代码语言:javascript复制/// 跳转新页面
/// 第一种方式 进入新页面 直接页面
Get.to(ProjectCloudVisiblePage());
/// 第二种方式 进入新页面 配置路由名称 建议这种统一配置
Get.toNamed(Routes.PROJECT_CLOUD_SELECT_MEMBERS);
///弹出当前页,并将一个新的[page]推入堆栈,就是删除就页面,使用新页面
Get.off(ProjectCloudVisiblePage());
/// Push a [page]和弹出几个页面在堆栈中,就是进入新页面,删除之前进栈的页面。比如场景(注册-手机号-其他注册信息-注册完了直接到主页,之前页面全部删掉。)
Get.offAll(ProjectCloudVisiblePage());
/// 同上,就是传路由名称
Get.offAllNamed(FXRoutes.PROJECT_CLOUD_SELECT_MEMBERS);
代码语言:javascript复制返回上一面 就一句
Get.back()
Routes类
代码语言:javascript复制abstract class Routes {
static const INITIAL = '/';
static const GUIDE = '/guide';
static const LOGIN = '/login';
static const CODE_LOGIN = '/code_login';
static const INPUT_CODE = '/input_code';
static const FORGET_PASSWORD = '/forget_password';
static const REGISTER = '/register';
static const PROJECT_CLOUD_VISIBLE = 'project_cloud_visible';
}
Pages类
代码语言:javascript复制class Pages {
static const INITIAL = FXRoutes.INITIAL;
static final routes = [
GetPage(
name: Routes.GUIDE,
page: () => SplashPage(),
transition: Transition.fadeIn),
GetPage(
name: Routes.INITIAL,
page: () => LoginPage(),
transition: Transition.fadeIn),
GetPage(
name: Routes.LOGIN,
page: () => LoginPage(),
transition: Transition.fadeIn),
GetPage(
name: Routes.CODE_LOGIN,
page: () => CodeLoginPage(),
transition: Transition.fadeIn),
GetPage(name: Routes.INPUT_CODE, page: () => InputCodePage()),
/// 这边使用依赖注入
GetPage(
name: FXRoutes.PROJECT_CLOUD_VISIBLE,
page: () => ProjectCloudVisiblePage(),
binding: BindingsBuilder(() => {
Get.lazyPut<ProjectCloudVisibleController>(
() => ProjectCloudVisibleController())
})),
}
4、状态管理 我一般一个page对应一个controller, controller来处理逻辑,控制page. 简单使用
代码语言:javascript复制///
controller 要继承 GetxController
class ProjectCloudListSearchController extends GetxController {
List<String> searchRecords = [];
TextEditingController editingController;
String searchText;
List<String> dataList = [];
@override
void onInit() {
// TODO: implement onInit
super.onInit();
editingController = TextEditingController();
/// 获取历史记录
ProjectCloudSearchCache.getProjectCloudSearchList().then((value) {
searchRecords.addAll(value);
update();
});
}
@override
void onClose() {
// TODO: implement onClose
super.onClose();
/// 添加缓存
ProjectCloudSearchCache.setProjectCloudSearchList(searchRecords);
}
/// 搜索请求 处理缓存
void searchRequest(String text,
{bool isRequest = true, bool clickRecords = false}) {
Utils.logs(text);
searchText = text;
if (clickRecords) {
editingController.text = text;
}
/// 请求接口
if (isRequest) {
dataList.add('1');
searchRecordsHandle();
}
update();
}
/// 删除记录
void deleteRecord(int index) {
searchRecords.removeAt(index);
update();
}
/// 清空记录
void clearRecords() {
searchRecords.clear();
/// 手动刷新 调用update
update();
}
/// 搜索记录处理
void searchRecordsHandle() {
if (searchText.isNotEmpty) {
if (!searchRecords.contains(searchText)) {
if (searchRecords.length >= 10) {
searchRecords.removeLast();
}
searchRecords.insert(0, searchText);
}
}
}
}
代码语言:javascript复制/// page页面
class ProjectCloudListSearchPage extends StatefulWidget {
@override
_ProjectCloudListSearchPageState createState() =>
_ProjectCloudListSearchPageState();
}
class _ProjectCloudListSearchPageState
extends State<ProjectCloudListSearchPage> {
FocusNode _focusNode = FocusNode();
/// 注入依赖 使用Get.put
final _searchC = Get.put(ProjectCloudListSearchController());
@override
void initState() {
// TODO: implement init State
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_focusNode.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: FXColor.color_text_66,
appBar: SearchWidget(
_searchC.editingController,
focusNode: _focusNode,
searchHintText: '输入作品标题',
searchCallBack: (searchText) {
_focusNode.unfocus();
_searchC.searchRequest(searchText);
},
onChanged: (searchText) {
_searchC.searchRequest(searchText, isRequest: false);
},
),
/// 使用GetBuilder包裹起来 调用update的时候 这边就会自动刷新数据。
body: GetBuilder<ProjectCloudListSearchController>(builder: (_) {
return EmptyUtils.isEmptyString(_searchC.searchText) &&
_searchC.searchRecords.isNotEmpty
? ProjectCloudSearchRecordsWidget(
_searchC.searchRecords,
valueCallBack: (searchText) {
_focusNode.unfocus();
_searchC.searchRequest(searchText, clickRecords: true);
},
deleteRecordCallBack: (index) {
_searchC.deleteRecord(index);
},
clearRecordCallBack: () {
_searchC.clearRecords();
},
)
: _searchC.dataList.isEmpty
? NoDataWidget()
: ListView.builder(
padding: const EdgeInsets.only(top: 10),
itemCount: 5,
itemBuilder: (context, index) {
return ProjectCloudListWidget();
});
}),
);
}
}
5、依赖注入 依赖注入也是我喜欢的,可以减少很多工作。 第一步
代码语言:javascript复制GetPage(
name: FXRoutes.PROJECT_CLOUD_VISIBLE,
page: () => ProjectCloudVisiblePage(),
/// 主要代码是这个 绑定
binding: BindingsBuilder(() => {
Get.lazyPut<ProjectCloudVisibleController>(
() => ProjectCloudVisibleController())
})),
第二步
代码语言:javascript复制/// 页面继承GetView<> 传依赖注入的控制器 这样就可以直接使用了,会发现这边没有 Get.put,或者Git.find, 使用的时候直接controller。 看源码可以知道GetView内部已经帮我们实现了。
class ProjectCloudVisiblePage extends GetView<ProjectCloudVisibleController> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarWidget(
'谁可见',
context: context,
actions: [
Container(
margin: const EdgeInsets.only(right: 15),
child: TextWidget(
'保存',
style: TextStyles.setTextStyle14(color: FXColor.blue_color),
clickCallBack: () {
/// 直接使用 controller
controller.saveVisibleSetting();
},
),
)
],
),
body: Column(
children: [
ProjectCloudSettingItemWidget(
'公开',
isSelect: false,
clickCallBack: () {
controller.allMemberVisitingSetting();
},
),
ProjectCloudSettingItemWidget(
'部分可见',
isSelect: true,
subText: '从组织架构中选择 >',
isShowDivider: false,
clickCallBack: () {
controller.pushToSelectMembers();
},
),
GetBuilder<ProjectCloudVisibleController>(builder: (_) {
return Container(
color: Colors.white,
padding: const EdgeInsets.only(bottom: 20, right: 15),
alignment: Alignment.centerRight,
/// 使用controller来获取数据
child: TextWidget(controller.selectMemberStr),
);
})
],
),
);
}
}
6、跨页面交互
代码语言:javascript复制在A界面处理数据,需要再B界面显示的时候,或者C界面,在或者D界面。只要注入了控制器。在其他界面就能拿到A界面的数据。
A界面注入
final _settingC = Get.put(ProjectCloudSettingController());
此刻A界面跳到B
Get.to(BPage);
B在跳到C
Get.to(CPage);
C在跳到D
Get.to(DPage);
D页面需要A界面的数据 注:这边要保证A一直在栈中。
直接 Get.find(); 就可以拿到数据。比一级一级传值简单方便舒适吧。
final ProjectCloudSettingController settingC = Get.find();
7、黑暗模式 可以参考前期写的博客。黑暗模式的适配