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

999 阅读7分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

基于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 相应的通用项目文章,喜欢的可以点点关注