美文网首页Flutter圈子
【flutter】ListView.builder封装各个页面通

【flutter】ListView.builder封装各个页面通

作者: 匿于烟火中 | 来源:发表于2020-04-03 18:49 被阅读0次

    flutter当中提供了无限加载的组件,再此基础上又做了一层封装。
    这个可复用的无限加载列表包括以下特点:

    • 上滑加载
    • 数据不满足加载条件,提示到达底部
    • 根据具体参数的变化,搜索并重新加载数据(可以轻松跟filter和search结合)
    • 不同的列表只需要传入任意定义的RowItem即可
    • 根据RESTFUL当中limit,offset分页机制加载

    组件封装当中比较复杂一点的就是dart如何进行泛型实例化。

    • RowItem父类
    import 'package:flutter/widgets.dart';
    
    abstract  class ListItemWidget extends StatelessWidget {
        const ListItemWidget(
          {Key key, this.item}
        ):super(key:key);
    
      final Map item;
      call(Map item)=>this;
    }
    
    • 无线加载列表组件
    import 'dart:async';
    
    import 'package:flutter/material.dart';
    import 'package:flutter/widgets.dart';
    import 'package:flutter_easyrefresh/easy_refresh.dart';
    import 'package:flutter_easyrefresh/material_header.dart';
    import 'package:flutter_lim/common/http.dart';
    import 'package:flutter_lim/widgets/listItem.dart';
    
    typedef RequestCallback = Stream<dynamic> Function({Map paramObj});
    typedef S ItemCreator<S extends ListItemWidget>(dynamic item); // new T()泛型实例化实现
    
    // 无限加载列表
    //使用InheritedWidget,每个列表管理自己的搜索参数
    class ShareParams extends InheritedWidget {
      ShareParams(
          {@required this.specialParams, this.data, this.count, Widget child})
          : super(child: child);
    
      final Map<String, dynamic> specialParams;
      final List<dynamic> data;
      final int count;
    
      static ShareParams of(BuildContext context) {
        return context.dependOnInheritedWidgetOfExactType<ShareParams>();
      }
    
      @override
      bool updateShouldNotify(ShareParams oldWidget) {
        Map<String, dynamic> oldParams = oldWidget.specialParams;
        bool isUpdate = false;
        if (this.specialParams.keys.length != oldParams.length) {
          isUpdate = true;
        } else {
          for (String key in this.specialParams.keys) {
            if (oldParams[key] == null ||
                oldParams[key] != this.specialParams[key]) {
              isUpdate = true;
              break;
            }
          }
        }
    
        return isUpdate;
      }
    }
    
    @immutable
    class InfiniteListViewWidget<T extends ListItemWidget> extends StatefulWidget {
      final RequestCallback request; //数据请求路径
      final List<dynamic> data; //初始化数据
      final int count; //列表总个数
      final ItemCreator<T> creator; //列表Item泛型实例化
      final Map<String, dynamic> specialParam; //特殊请求参数,若无须共享参数,传值
      final Function refresh;
      InfiniteListViewWidget(this.request, this.data, this.count, this.creator,
          {this.specialParam, this.refresh});
    
      @override
      _InfiniteListViewWidgetState<T> createState() =>
          new _InfiniteListViewWidgetState<T>(
              this.request, this.data, this.count, this.creator,
              specialParam: this.specialParam, refresh: this.refresh);
    }
    
    @override
    class _InfiniteListViewWidgetState<T extends ListItemWidget>
        extends State<InfiniteListViewWidget> {
      static const loadingTag = {"position": "bottom"}; //表尾标记
      Http http = new Http();
      InfiniteListParamObj infiParams;
      RequestCallback request; //数据请求
      int count; //列表数据总数量
      List<dynamic> data;
      ItemCreator<T> creator;
      @optionalTypeArgs
      Map<String, dynamic> specialParam; //特殊请求参数
      Function refresh;
    
      EasyRefreshController _refreshController = new EasyRefreshController();
    
      _InfiniteListViewWidgetState(
          this.request, this.data, this.count, this.creator,
          {this.specialParam, this.refresh});
    
      @override
      void initState() {
        super.initState();
      }
    
      void didChangeDependencies() {
        super.didChangeDependencies();
        if (ShareParams.of(context) != null) {
          print(
              'LISTEN PARAMS didChange=>${ShareParams.of(context).specialParams}');
          print('LISTEN PARAMS didChange=>${ShareParams.of(context).data}');
          this.specialParam = ShareParams.of(context).specialParams;
          this.data = ShareParams.of(context).data;
          this.count = ShareParams.of(context).count;
        }
        if (this.specialParam != null) {
          this._setInfiniteParams(this.specialParam);
        }
      }
    
      @override
      Widget build(BuildContext context) {
    //EasyRefresh是下拉刷新组件,不需要的话可以直接去掉
        return EasyRefresh(
          header: MaterialHeader(),
          child: ListView.builder(
            itemCount: this.data.length,
            itemBuilder: (BuildContext context, int index) {
              var word = this.data[index];
              var nextWord;
              if (index == this.data.length - 1) {
                nextWord = null;
              } else {
                nextWord = this.data[index + 1];
              }
              if (nextWord == null && this.data.length == index + 1) {
                // 根据返回的count
                final curCount = this.data.length;
                if (curCount < this.count) {
                  //offset + limit  >= count 的时候不再下拉
                  this.infiParams.offset = this.data.length;
                  //获取数据
                  _retrieveData(this.resolveListData);
                  //加载时显示loading
                  return Column(
                    children: <Widget>[
                      creator(word),
                      Container(
                        padding: const EdgeInsets.all(16.0),
                        alignment: Alignment.center,
                        child: SizedBox(
                            width: 24.0,
                            height: 24.0,
                            child: CircularProgressIndicator(strokeWidth: 2.0)),
                      )
                    ],
                  );
                } else {
                  //加载数据总数已经超过count了不再加载
                  return Column(
                    children: <Widget>[
                      creator(word),
                      Container(
                          alignment: Alignment.center,
                          padding: EdgeInsets.all(16.0),
                          child: Text(
                            "没有更多了",
                            style: TextStyle(color: Colors.grey),
                          ))
                    ],
                  );
                }
              }
    //由于build方法中返回的Widget必须实例化,所以要实现泛型实例化
              T item = creator(word);
              return item;
            },
          ),
          controller: _refreshController,
          onRefresh: () async {
            this.refresh == null
                ? _refreshController.finishRefresh(success: true)
                : this.refresh();
          },
        );
      }
    
      void _setInfiniteParams(Map<String, dynamic> specialParam,
          {int limit, int offset, String ordering}) {
        if (this.infiParams == null) {
          limit = limit != null ? limit : 10;
          offset = offset != null ? offset : 0;
          ordering = ordering != null ? ordering : '-create_time';
          this.infiParams =
              new InfiniteListParamObj(limit, offset, ordering, specialParam);
        } else {
          this.infiParams.paramsObj = specialParam;
        }
      }
    
      void _retrieveData(Function resovle) {
        Map<String, dynamic> paramObj = this.infiParams.getParams();
        request(paramObj: paramObj).listen(resovle);
      }
    
      void resolveListData(dynamic data) {
        this.count = data['count'];
        setListData(data['results']);
      }
    
      void setListData(dynamic list) {
        this.data.addAll(list);
        setState(() {});
      }
    }
    
    • 列表默认参数,可以根据具体的设计修改
    @override
    class InfiniteListParamObj {
      int limit = 10;
      int offset = 0;
      String ordering = '';
      Map<String, dynamic> paramsObj = {};
      InfiniteListParamObj(this.limit, this.offset, this.ordering, this.paramsObj);
      Map<String, dynamic> getParams() {
        Map<String, dynamic> basic = {
          "limit": this.limit,
          "offset": this.offset,
          "ordering": this.ordering
        };
        basic.addAll(this.paramsObj);
        return basic;
      }
    
      void resetBasicParams() {
        this.limit = 10;
        this.offset = 0;
      }
    }
    
    • 如何使用
     Expanded(
              child: ShareParams(
            specialParams: this.paramsObj,
            data: this.dataList,//数据列表
            count: this.count,//数据总count
            child: new InfiniteListViewWidget<ProductItem>(//ProductItem具体集成自ListItemWidget的列表项目
              getUniqueProdList,//数据加载url
              this.dataList,
              this.count,
              (item) => new ProductItem(item),
              specialParam: this.paramsObj,//列表搜索参数
              refresh: this.onRefresh,//自定义列表刷新的方法
            ),
          ));
    

    相关文章

      网友评论

        本文标题:【flutter】ListView.builder封装各个页面通

        本文链接:https://www.haomeiwen.com/subject/sfukphtx.html