基于GetX 搭建通用flutter 项目《五》(基于GetX 进行动态刷新)

基于GetX 搭建通用flutter 项目《一》

基于GetX 搭建通用flutter 项目《二》(界面规范抽象类)

基于GetX 搭建通用flutter 项目《三》(暗黑模式)

基于GetX 搭建通用flutter 项目《四》(国际化)

最后还是到了这一步,经过 基于GetX 搭建通用flutter 项目《一》基于GetX 搭建通用flutter 项目《二》(界面规范抽象类)这两篇文章的讲解。
大家应该都会纳闷,不是说好的GetX吗?,我也就在基于GetX 搭建通用flutter 项目《三》(暗黑模式)这里看到出现过和使用过,其他的毛都没有。
你是不是不想分享啊,NONONO,少侠莫急,我只是想先把动态刷新所依赖的抽象类讲解一下,其实项目里用的GetX抽象类,也是基于第二篇的抽象类,对项目进行了定制化的扩展,如果看过项目代码的人,应该理解了我的思路,其实就是抽象类纯粹点,组合方式多一点 好,还是老规矩,上“技师”.

  • DEMO更新日志

    2022-07-14 完成国际化
    2022-06-22 完成暗黑模式功能开发
    2022-06-16 完成项目基础架构
    

您能在这里看到啥

  1. GetView抽象类
  2. GetList抽象类
  3. GetController抽象类
  4. 使用例子

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抽象类

这里面我就直接controllerlistcontroller 一起来讲解了,因为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.

当然接下的时间里我也会总结OCswift 相应的通用项目文章,喜欢的可以点点关注

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容