本文已参与「新人创作礼」活动,一起开启掘金创作之路
基于GetX 搭建通用flutter 项目《二》(界面规范抽象类)
基于GetX 搭建通用flutter 项目《三》(暗黑模式)
最后还是到了这一步,经过 基于GetX 搭建通用flutter 项目《一》基于GetX 搭建通用flutter 项目《二》(界面规范抽象类)这两篇文章的讲解,大家应该都会纳闷,不是说好的GetX吗?,我也就在基于GetX 搭建通用flutter 项目《三》(暗黑模式)这里看到出现过和使用过,其他的毛都没有,你是不是不想分享啊,NONONO,少侠莫急,我只是想先把动态刷新所依赖的抽象类讲解一下,其实项目里用的GetX抽象类,也是基于第二篇的抽象类,对项目进行了定制化的扩展,如果看过项目代码的人,应该理解了我的思路,其实就是抽象类纯粹点,组合方式多一点 好,还是老规矩,上“技师”.
-
DEMO更新日志
2022-07-14 完成国际化 2022-06-22 完成暗黑模式功能开发 2022-06-16 完成项目基础架构
您能在这里看到啥
- GetView抽象类
- GetList抽象类
- GetController抽象类
- 使用例子
GetView抽象类
// ignore: must_be_immutable
abstract class NormaGetxView<T extends NormalGetxController> extends GetView<T>
with AbstractAttribute, AbstractWidget {
NormaGetxView({Key? key}) : super(key: key);
@override
PageState get pageState => controller.pageState.value;
@override
Widget build(BuildContext context) {
return createScaffol(
context: context,
safeAreatop: safeAreatop,
safeAreabottm: safeAreabottm,
pageState: pageState,
title: title,
backgroundColor: backgroundColor,
navbackcolor: navbackcolor,
resizeToAvoidBottomInset: resizeToAvoidBottomInset);
}
/// 抽离通用colum 方法,用layoutbuilder包裹的目的
/// 为了解决web 开发时,设置最大布局
/// 分为 createObxWidget() 和 createObxColumWidget()
@override
Widget createColumWidget(BuildContext context) {
return Container(
alignment: Alignment.center,
child: LayoutBuilder(
builder: (context, constraints) {
/// 这个方法是为了设置界面在web端的时候,
/// 也能让界面拉伸的情况正常显示的宽度最大值
/// 不过一般不适配web的话,没必要这样写
/// 也可以不用LayoutBuilder包裹,看你使用情况吧
configlayoutbuiderConstraints(constraints);
return Container(
alignment: Alignment.centerLeft,
width: configSizeBoxWidth(constraints),
child: createObxWidget(),
);
},
),
);
}
/// 为 getx 新增包裹方法
/// 我这里使用Obx把整个界面包裹着,
/// 为了更好的刷新
Widget createObxWidget() {
return Obx(
() => createObxColumWidget(),
);
}
/// getx 真实包裹的colum 方法
/// 这个就和我们通用抽象类的方法差不多
/// 我这里还是把它分成了
/// header + body
Widget createObxColumWidget() {
return Column(
children: [
createHeaderWidget(),
Expanded(
child: createBody(Get.context!),
),
],
);
}
/// 获取 屏幕 最大尺寸
configlayoutbuiderConstraints(BoxConstraints constraints) {
controller.configsiezw(configSizeBoxWidth(constraints));
}
double configSizeBoxWidth(BoxConstraints constraints) {
return HzyNormalUtils.configSizeMaxW(constraints.maxWidth);
}
}
这样我们的GetView 的抽象类就做好了,是不是很简单,下面我们来看一下,细心的小伙伴,肯定也发现了个东东. 那就是我们抽象类的NormalGetxController通用控制器.不过不要心急,我会在下面讲解一下的. 好了我们来看一下GetListView抽象类
GetList抽象类
由于是列表页,这里我们需要上下啦刷新控件,我这里使用的是flutter_easyrefresh这个刷新控件.下面我们就看一下我是怎么使用的,当然由于我们使用的Get,我也把界面和逻辑完全抽离了.先讲一下界面
// ignore: must_be_immutable
abstract class NormalGetxListView<T extends NormalGetxListController>
extends NormaGetxView<T> with AbstracRefreshWidget {
NormalGetxListView({Key? key}) : super(key: key);
@override
Widget createBody(BuildContext context) {
return createRefreshWidget(context);
}
/// 创建列表刷新控件
@override
Widget createRefreshWidget(BuildContext context) {
return EasyRefresh(
key: key,
/// 这里边把控制器的创建也交给了Controller
controller: controller.refreshController ?? EasyRefreshController(),
onRefresh: () async {
/// 下啦刷新触发方法也是交给了控制器
controller.configRefresh();
},
onLoad: () async {
/// 同样的上啦加载也是交给了控制器
controller.configLoading();
},
child: createListView(context),
header: createHeader(),
footer: createFooter(),
emptyWidget: createEmptyWidget(),
);
}
/// 这里算是新增了自定义刷新header的方法
/// 都是为了使用者可以完全的自定义
Header? createHeader() {
return ClassicalHeader(、
refreshingText: '正在刷新...',
refreshedText: '刷新成功',
refreshReadyText: '松开刷新',
refreshFailedText: '刷新失败',
refreshText: '下拉刷新',
showInfo: false,
textColor: CommentColorS.col000000,
);
}
/// 这里算是新增了自定义刷新footer的方法
Footer? createFooter() {
return ClassicalFooter(
loadText: "上啦加载更多数据",
loadReadyText: "松开加载",
loadingText: "正在加载...",
loadedText: "加载成功",
loadFailedText: "加载失败",
noMoreText: "没有更多数据了~",
showInfo: false,
textColor: CommentColorS.col000000,
);
}
}
我们也是引用了我们之前AbstracRefreshWidget列表抽象类,这样就减少了,我们重复的写,只需要重写需要自定义的方法即可.我们这边总共重写2个方法,来实现GetList的抽象类,具体就不多少了,代码上都有讲解.
GetController抽象类
这里面我就直接controller 和 listcontroller 一起来讲解了,因为listcontroller也是继承了controller,看代码
abstract class NormalGetxController extends GetxController {
/// 界面状态值,用于刷新界面 显示效果
var pageState = PageState.initializedState.obs;
/// 配置点击失败界面 刷线方法
/// 这个是当失败界面点击刷新的预留触发方法,
/// 子类可以重写这个方法 来实现数据刷新
configreload(){}
}
abstract class NormalGetxListController extends NormalGetxController
implements AbstractNetWork {
/// 刷新控制器
EasyRefreshController? refreshController;
/// 页数
int page = 1;
@override
void onInit() {
super.onInit();
refreshController = EasyRefreshController();
}
// 下啦刷新触发事件
configRefresh() async {
page = 1;
getnetworkdata(1, configNetWorkParmas());
}
// 上啦加载更多触发事件
configLoading() async {
page++;
getnetworkdata(2, configNetWorkParmas());
}
/// 网络请求 参数方法
@override
Map<String, dynamic>? configNetWorkParmas() {
return null;
}
/// 网络请求数据
@override
void getnetworkdata(int? type, Map<String, dynamic>? info) async {}
/// 结束刷新方法
/// type == 1 代表下拉刷新
/// tyep == 2 代表上啦加载
void endRefresh({int? type, PageState? state}) {
bool success = true;
bool noMore = false;
/// 根据状态值 配置是否有更多数据
if (state == PageState.noMoreDataState) {
noMore = true;
}
/// 根据状态值,判断数据是否请求成功
if (state == PageState.errorState ||
state == PageState.erroronlyTotal ||
state == PageState.errorshowRelesh) {
success = false;
}
if (refreshController != null) {
if (type == 1) {
refreshController!.finishRefresh(success: success);
refreshController!.resetLoadState();
} else if (type == 2) {
/// 在这里 配置上啦加载 是否有更多数据
refreshController!.finishLoad(success: success, noMore: noMore);
}
}
pageState.value = state!;
}
从控制器看到,我们在界面里所需要做的上下啦刷新事件,以及网络请求,业务逻辑,都会在这里完成,这样view 只关心显示问题就行,所有的状态都是通过控制器来控制的.
到此,这个抽象类算是封装完成,下面看看到真的项目中应该怎么使用呢
使用例子
相对来说,由于上面的抽象类是通用型的,我一般会在新的项目里,以上面的为基准,会在封装一个适合当前项目的抽象类.这里我就只讲一下适用本项目的控制器抽象类,然后再讲一下界面使用
本项目控制器抽象类
abstract class CommonGetXController extends NormalGetxController {
/// 项目中 使用的失败界面的标识,用于使用者 显示不同的界面
/// 具体 使用,一般是通过网络请求,进行逻辑处理
var placeHoldType = CommonPlaceHoldType.nonetwork;
}
abstract class CommonGetXListController extends NormalGetxListController {
/// 项目中 使用的失败界面的标识,用于使用者 显示不同的界面
/// 具体 使用,一般是通过网络请求,进行逻辑处理
var placeHoldType = CommonPlaceHoldType.nonetwork;
/// 这个就是上面 失败出发方法,
/// 我这里就简单的用了,方法是触发登录,还是触发列表下啦刷新
/// 两个事件,这个可根据你们自己业务进行扩展
@override
configreload() {
if (UserStateController.isLogin) {
refreshController?.callRefresh();
} else {
currentToPage(LoginPageId.login);
}
}
}
列表事例
请看项目重的 home_list_v.dart 和 home_list_c.dart 这两个dart类的实现,由于代码多,就不在这显示.
到此,基本上想分享的都讲完了,如果不理解可以在下面评论,或者多看看项目代码.喜欢的可以点点赞,你们的鼓励,就是我前进的东西.谢谢
hzy_normal_widget 是我在使用GetX搭建项目时,总结的一些通用开发控件,方便我们在开发的时候,减少重复性界面代码的创建.
ttcomment 通用项目的界面接口基类,和一些通用工具类,喜欢的可以点点star.
当然接下的时间里我也会总结OC 和 swift 相应的通用项目文章,喜欢的可以点点关注