zoukankan      html  css  js  c++  java
  • Flutter实战视频-移动电商-35.列表页_上拉加载更多制作

    35.列表页_上拉加载更多制作

    右侧列表上拉加载配合类别的切换

    上拉加载需要一个page参数,当点击大类或者小类的时候,这个page就要变成1

    provide内定义参数

    首先我们需要定义一个page的变量

    下图是我们之前在首页的时候做的上拉加载代码,之前属性noMoreText我们没有设置值,这里我也需要把这个属性加入到provide里面去。

    在大类和小类的初始化的方法内,都需要把page设置为1,然后把提示信息设置为空

    然后我们需要做page增加的方法,上拉刷新的时候,这个page值是不断的增加的

    再增加改变我们的noMoreText的值的方法

    引入fresh插件

    category_page.dart页面引入上拉刷新的插件

    import 'package:flutter_easyrefresh/easy_refresh.dart';

    我们在右侧的列表类里面,在列表的地方外层嵌套easy_refresh

    我们复制首页之前写好的代码过来。

    中间红框内是和原来的代码,上面refreshFooter部分是复制首页的代码过来的。下面的loadMore事件是自己写的

    再复制首页的footerKey

     GlobalKey<RefreshFooterState> _footerkey=new GlobalKey<RefreshFooterState>();

    这样key这里就不报错了。

    noMoreText用状态 管理里面的值

    noMoreText: Provide.value<ChildCategory>(context).noMoreText,

    效果展示

    loadMore回调函数补充完整

    上拉加载更多和我们加载大类和小类是一样的 我们复制右侧的列表的数据获取的方法

    下图是复制的右侧加载列表数据的方法

    下面这里,因为我们是不断的累计list的数据的 所以不能再使用等号了。

    修改为使用addAll的方法

    调用我们获取数据的方法

    修正一个地方,这个方法添加的地方是在最后一个花括号结束的上方 复制这个getMoreList的方法

    有了上拉刷新的效果。但是点击小类的时候列表数据,不变化了

     

    修正一个错误的地方

    上拉刷新的效果

    page需要++

    我们在调用上拉刷险的时候,没有调用page++

    存在问题

    当我们一个类别上拉刷新了几次后,滚动条滚动到最下面了。当我们再去点击别的大类的时候,滚动条还是在这个位置上。滚动条没有滚动到最上面

    只要切换大类的是时候,就返回我们的顶部,好用scrollController的jumpTo方法 跳转到0.0的位置

    最终代码:

    provide/child_category.dart

    import 'package:flutter/material.dart';
    import '../model/category.dart';
    
    class ChildCategory with ChangeNotifier{
     List<BxMallSubDto> childCategoryList=[];
     int childIndex=0;//子类高亮索引
     String categoryId='4';//大类ID 白酒的id 默认为4
     String subId='';//小类ID
     int page=1;
     String noMoreText='';//显示没有数据的文字
      //大类切换逻辑
      getChildCategory(List<BxMallSubDto> list,String id){
        page=1;
        noMoreText='';
        childIndex=0;//每次点击大类,小类的索引都要清空掉
        categoryId=id;
        BxMallSubDto all=BxMallSubDto();
        all.mallCategoryId="00";
        all.mallCategoryId="00";
        all.comments="null";
        all.mallSubName='全部';
        childCategoryList=[all];
        //childCategoryList=list;
        childCategoryList.addAll(list);
        notifyListeners();//监听
      }
      //改变子类索引,indexs是从哪里来的呢?从我们具体的类中进行传递
      changeChildIndex(index,String id){
        page=1;
        noMoreText='';
        childIndex=index;//把传递过来的index赋值给我们的childIndex
        subId=id;
        notifyListeners();//通知
      }
      //增加Page的方法
      addPage(){
        page++;
        //notifyListeners();//这里不需要通知,因为我们只是page+1了并没有页面数据上的变化
      }
      //改变noMore的方法
      changeNoMore(String text){
        noMoreText=text;
        notifyListeners();//通知
      }
    }

    provide/category_goods_list.dart

    import 'package:flutter/material.dart';
    import '../model/categoryGoodsList.dart';
    
    class CategoryGoodsListProvide with ChangeNotifier{
     List<CategoryListData> goodsList=[];
     //点击大类时候更换商品列表
     getGoodsList(List<CategoryListData> list){
       goodsList=list;
       notifyListeners();
     }
    
     getMoreList(List<CategoryListData> list){
       goodsList.addAll(list);
       notifyListeners();
     }
    
    }
    import 'package:flutter/material.dart';
    import '../service/service_method.dart';
    import 'dart:convert';
    import '../model/category.dart';
    import '../model/categoryGoodsList.dart';
    import 'package:flutter_screenutil/flutter_screenutil.dart';
    import 'package:provide/provide.dart';
    import '../provide/child_category.dart';
    import '../provide/category_goods_list.dart';
    import 'package:flutter_easyrefresh/easy_refresh.dart';
    
    class CategoryPage extends StatefulWidget {
      @override
      _CategoryPageState createState() => _CategoryPageState();
    }
    
    class _CategoryPageState extends State<CategoryPage> {
      @override
      Widget build(BuildContext context) {
        //_getCategory();
        return Scaffold(
          appBar: AppBar(title: Text('商品分类'),),
          body: Container(
            child: Row(
              children: <Widget>[
                LeftCategoryNav(),
                Column(
                  children: <Widget>[
                    RightCategoryNav(),
                    CategoryGoodsList()
                  ],
                )
              ],
            ),
          ),
        );
      }
    
     
    }
    
    //左侧大类导航
    class LeftCategoryNav extends StatefulWidget {
      @override
      _LeftCategoryNavState createState() => _LeftCategoryNavState();
    }
    
    class _LeftCategoryNavState extends State<LeftCategoryNav> {
      List list=[];
      var listIndex=0;
      @override
      void initState() { 
        super.initState();
        _getCategory();//请求接口的数据
        _getGoodsList();//参数是可选的默认是4 所以这里可以不用传值
      }
      @override
      Widget build(BuildContext context) {
        return Container(
           ScreenUtil().setWidth(180),
          decoration: BoxDecoration(
            border: Border(
              right: BorderSide(1.0,color: Colors.black12),//有边框
            )
          ),
          child: ListView.builder(
            itemCount: list.length,
            itemBuilder: (contex,index){
              return _leftInkWell(index);
            },
          ),
        );
      }
    
      Widget _leftInkWell(int index){
        bool isClick=false;
        isClick=(index==listIndex)?true:false;
        return InkWell(
          onTap: (){
            setState(() {
             listIndex=index; 
            });
            var childList=list[index].bxMallSubDto;//当前大类的子类的列表
            var categoryId=list[index].mallCategoryId;//大类的id
            Provide.value<ChildCategory>(context).getChildCategory(childList,categoryId);
            _getGoodsList(categoryId:categoryId);
          },
          child: Container(
            height: ScreenUtil().setHeight(100),
            padding: EdgeInsets.only(left:10.0,top:10.0),
            decoration: BoxDecoration(
              color: isClick?Color.fromRGBO(236, 236, 236, 1.0): Colors.white,
              border: Border(
                bottom: BorderSide( 1.0,color: Colors.black12)
              )
            ),
            child: Text(
              list[index].mallCategoryName,
              style: TextStyle(fontSize: ScreenUtil().setSp(28)),//设置字体大小,为了兼容使用setSp
            ),
          ),
        );
      }
       void _getCategory() async{
        await request('getCategory').then((val){
          var data=json.decode(val.toString());
          //print(data);
          CategoryModel category= CategoryModel.fromJson(data);
          setState(() {
           list=category.data; 
          });
          Provide.value<ChildCategory>(context).getChildCategory(list[0].bxMallSubDto,list[0].mallCategoryId);
        });
      }
    
      void _getGoodsList({String categoryId}) {
        var data={
          'categoryId':categoryId==null?'4':categoryId,//白酒的默认类别
          'categorySubId':"",
          'page':1
        };
        request('getMallGoods',formData: data).then((val){
          var data=json.decode(val.toString());
          CategoryGoodsListModel goodsList=CategoryGoodsListModel.fromJson(data);//这样就从json'转换成了model类
          //print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>:${goodsList.data[0].goodsName}');
          // setState(() {
          //  list=goodsList.data; 
          // });
          Provide.value<CategoryGoodsListProvide>(context).getGoodsList(goodsList.data);
        });
      }
    }
    
    class RightCategoryNav extends StatefulWidget {
      @override
      _RightCategoryNavState createState() => _RightCategoryNavState();
    }
    
    class _RightCategoryNavState extends State<RightCategoryNav> {
      //List list = ['名酒','宝丰','北京二锅头','舍得','五粮液','茅台','散白'];
      @override
      Widget build(BuildContext context) {
        return Provide<ChildCategory>(
          builder: (context,child,childCategory){
            return  Container(
              height: ScreenUtil().setHeight(80),
               ScreenUtil().setWidth(570),//总的宽度是750 -180
              decoration: BoxDecoration(
                color: Colors.white,//白色背景
                border: Border(
                  bottom: BorderSide( 1.0,color: Colors.black12)//边界线
                )
              ),
              child: ListView.builder(
                scrollDirection: Axis.horizontal,
                itemCount: childCategory.childCategoryList.length,
                itemBuilder: (context,index){
                  return _rightInkWell(index,childCategory.childCategoryList[index]);
                },
              ),
            );
          }
        );
      }
    
      Widget _rightInkWell(int index,BxMallSubDto item){
        bool isClick=false;
        isClick=(index==Provide.value<ChildCategory>(context).childIndex)?true:false;
    
        return InkWell(
          onTap: (){
            Provide.value<ChildCategory>(context).changeChildIndex(index,item.mallSubId);
            _getGoodsList(item.mallSubId);
          },//事件留空
          child: Container(//什么都加一个container,这样好布局
            padding: EdgeInsets.fromLTRB(5.0, 10.0, 5.0, 10.0),//上下是10 左右是5.0
            child: Text(
              item.mallSubName,
              style:TextStyle(
                fontSize: ScreenUtil().setSp(28),
                color: isClick?Colors.pink:Colors.black
              ),
            ),
          ),
        );
      }
      void _getGoodsList(String categorySubId) {
        var data={
          'categoryId':Provide.value<ChildCategory>(context).categoryId,//大类ID
          'categorySubId':categorySubId,
          'page':1
        };
        request('getMallGoods',formData: data).then((val){
          var data=json.decode(val.toString());
          CategoryGoodsListModel goodsList=CategoryGoodsListModel.fromJson(data);//这样就从json'转换成了model类
          if(goodsList.data==null){
            Provide.value<CategoryGoodsListProvide>(context).getGoodsList([]);
          }else{
            Provide.value<CategoryGoodsListProvide>(context).getGoodsList(goodsList.data);
          }
          
        });
      }
    }
    
    //商品列表 ,可以上拉加载
    class CategoryGoodsList extends StatefulWidget {
      @override
      _CategoryGoodsListState createState() => _CategoryGoodsListState();
    }
    
    class _CategoryGoodsListState extends State<CategoryGoodsList> {
       GlobalKey<RefreshFooterState> _footerkey=new GlobalKey<RefreshFooterState>();
       var scrollController=new ScrollController();
      @override
      void initState() {
        //_getGoodsList();
        super.initState();
      }
      @override
      Widget build(BuildContext context) {
        return Provide<CategoryGoodsListProvide>(
          builder: (context,child,data){
            try {
              if(Provide.value<ChildCategory>(context).page==1){
                //列表位置,放到最上边
                scrollController.jumpTo(0.0);
              }
            } catch (e) {
              print('进入页面第一次初始化:${e}');
            }
            if(data.goodsList.length>0){
                return  Expanded(
                  child: Container(
                     ScreenUtil().setWidth(570),
                    //height: ScreenUtil().setHeight(974),
                    child: EasyRefresh(
                       refreshFooter: ClassicsFooter(
                          key: _footerkey,
                          bgColor: Colors.white,//背景颜色
                          textColor: Colors.pink,//粉红色
                          moreInfoColor: Colors.white,
                          showMore: true,
                          noMoreText: Provide.value<ChildCategory>(context).noMoreText,//具体也不知道到没到底 所以这里直接设置为空就不再显示了
                          moreInfo: '加载中',
                          loadReadyText: '上拉加载......',//网上拉 显示的文字
                        ),
                        child:   ListView.builder(
                          controller: scrollController,
                          itemCount: data.goodsList.length,
                          itemBuilder: (contex,index){
                            return _listWidget(data.goodsList,index);
                          },
                        ),
                        loadMore: () async{
                          print('上拉加载更多......');
                          _getMoreList();
                        },
                    )
                  ),
                );
            }else{
              return Text('暂时没有数据');
            }
           
          },
        );
      }
       
      void _getMoreList() {
         Provide.value<ChildCategory>(context).addPage();
          var data={
            'categoryId':Provide.value<ChildCategory>(context).categoryId,//大类ID
            'categorySubId':Provide.value<ChildCategory>(context).subId,
            'page':Provide.value<ChildCategory>(context).page
          };
          request('getMallGoods',formData: data).then((val){
            var data=json.decode(val.toString());
            CategoryGoodsListModel goodsList=CategoryGoodsListModel.fromJson(data);//这样就从json'转换成了model类
            if(goodsList.data==null){
              Provide.value<ChildCategory>(context).changeNoMore('没有更多了');
            }else{
              Provide.value<CategoryGoodsListProvide>(context).getMoreList(goodsList.data);
            }
            
          });
        }
    
    
      //}
      
    
      Widget _goodsImage(List newList,index){
        return Container(
           ScreenUtil().setWidth(200),//设置200的宽度 限制
          child: Image.network(newList[index].image),
        );
      }
      Widget _goodsName(List newList,index){
        return Container(
          padding: EdgeInsets.all(5.0),//上下左右都是5.0的内边距
           ScreenUtil().setWidth(370),//370是一个大约的值
          child: Text(
            newList[index].goodsName,
            maxLines: 2,//最多显示2行内容
            overflow: TextOverflow.ellipsis,
            style: TextStyle(fontSize: ScreenUtil().setSp(28)),//字体大小
          ),
        );
      }
    
      Widget _goodsPrice(List newList,index){
        return Container(
          margin: EdgeInsets.only(top:20.0),//和上面的外间距
           ScreenUtil().setWidth(370),//370是一个大约的值
          child: Row(
            children: <Widget>[
              Text(
                '价格¥${newList[index].presentPrice}',
                style: TextStyle(color: Colors.pink,fontSize: ScreenUtil().setSp(30)),
              ),
              Text(
                '价格¥${newList[index].oriPrice}',
                style: TextStyle(
                  color: Colors.black26,
                  decoration: TextDecoration.lineThrough
                ),//删除线的样式
              )
            ],
          ),
        );
      }
    
      Widget _listWidget(List newList,int index){
        return InkWell(
          onTap: (){},
          child: Container(
            padding: EdgeInsets.only(top:5.0,bottom:5.0),
            decoration: BoxDecoration(
              color: Colors.white,
              border: Border(
                bottom: BorderSide( 1.0,color: Colors.black12)
              )
            ),
            child: Row(
              children: <Widget>[
                _goodsImage(newList,index),
                Column(
                  children: <Widget>[
                    _goodsName(newList,index),
                    _goodsPrice(newList,index)
                  ],
                )
              ],
            ),
          ),
        );
      }
    }
    category_page.dart
  • 相关阅读:
    自定义分页二
    CheckBox实现跨页面多选
    正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。
    DropDownList下拉框多选
    通用查询
    AutoCAD自动加载DLL文件的方法
    软件开发(团队管理)
    正确地做事与做正确的事
    C#.NET实现邮件的发送
    多附件的上传
  • 原文地址:https://www.cnblogs.com/wangjunwei/p/10721080.html
Copyright © 2011-2022 走看看