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

上拉加载需要一个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();
} }

category_page.dart

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(
width: ScreenUtil().setWidth(180),
decoration: BoxDecoration(
border: Border(
right: BorderSide(width: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(width: 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),
width: ScreenUtil().setWidth(570),//总的宽度是750 -180
decoration: BoxDecoration(
color: Colors.white,//白色背景
border: Border(
bottom: BorderSide(width: 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(
width: 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(
width: ScreenUtil().setWidth(200),//设置200的宽度 限制
child: Image.network(newList[index].image),
);
}
Widget _goodsName(List newList,index){
return Container(
padding: EdgeInsets.all(5.0),//上下左右都是5.0的内边距
width: 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),//和上面的外间距
width: 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(width: 1.0,color: Colors.black12)
)
),
child: Row(
children: <Widget>[
_goodsImage(newList,index),
Column(
children: <Widget>[
_goodsName(newList,index),
_goodsPrice(newList,index)
],
)
],
),
),
);
}
}

.

Flutter移动电商实战 --(35)列表页_上拉加载更多制作的更多相关文章

  1. Flutter实战视频-移动电商-35.列表页_上拉加载更多制作

    35.列表页_上拉加载更多制作 右侧列表上拉加载配合类别的切换 上拉加载需要一个page参数,当点击大类或者小类的时候,这个page就要变成1 provide内定义参数 首先我们需要定义一个page的 ...

  2. Flutter移动电商实战 --(20)首页上拉加载更多功能的制作

    这节课学习一下上拉加载效果,其实现在上拉加载的插件有很多,但是还没有一个插件可以说完全一枝独秀,我也找了一个插件,这个插件的优点就是服务比较好,作者能及时回答大家的问题.我觉的选插件也是选人,人对了, ...

  3. 移动端h5列表页上拉加载更多

    背景 上星期公司要求做一个回收书籍的h5给安卓用,里面有一个功能是回收记录列表.设计师那边出的稿子是没有要求分页或者是上拉刷新的,但是众所周知,列表页数据很多的情况下,h5加载是很慢的.所以我一开始是 ...

  4. Flutter: 下拉刷新,上拉加载更多

    import 'package:flutter/material.dart'; import 'package:english_words/english_words.dart'; void main ...

  5. iOS MJRefresh的使用 (列表上拉加载更多)

    pod 'MJRefresh' import MJRefresh 加载更多 let footView = MJRefreshAutoNormalFooter(refreshingBlock:{ //去 ...

  6. Flutter实战视频-移动电商-32.列表页_小类高亮交互效果制作

    32.列表页_小类高亮交互效果制作 点击大类右侧的横向的小类红色显示当前的小类别 解决之前溢出的问题: 先解决一个bug,之前右侧的这里设置的高度是1000,但是有不同的虚拟机和手机设别的问题造成了溢 ...

  7. Flutter移动电商实战 --(28)列表页_商品列表后台接口调试

    主要调试商品列表页的接口 这个接口是最难的因为有大类.小类还有上拉加载 先配置接口 config/service_url.dart //const serviceUrl='http://test.ba ...

  8. Flutter移动电商实战 --(34)列表页_小BUG的修复

    当高粱酒的子类没有数据返回的时候就会报错. 解决接口空数据报错的问题 没有数据的时候,给用户一个友好的提示, 我们没有数据的时候还要告诉用户,提示一下他没有数据,在我们的右侧列表的build方法内去判 ...

  9. Flutter移动电商实战 --(33)列表页_子类和商品列表交互效果

    主要实现点击小类下面的列表跟着切换 获取右侧下面的列表信息,即要传递大类的id也要传递小类的,所以需要把左侧的大类的id也要Provide化 可以看下网站上的接口说明: https://jspang. ...

随机推荐

  1. 字体图标iconfont

    字体图标的作用: 1. 可以做出图片一样可以做的事情, 改变透明度, 旋转度,等... 2. 但是本质其实是文字,可以很随意的改变颜色, 产生阴影,透明效果等 3. 本身体积更小,但携带的信息并没有消 ...

  2. MVC模板页使用

    这里我们要做一个公共的模板,样式如下: 内容 ·asp.net mvc如何创建模板??1.在/Views/Shared/中右键-添加-视图 2.重命名为”HeadLayout”,勾选”创建为分部视图” ...

  3. openssh升级

    转载:(感谢作者) centos7 升级openssh到openssh-8.0p1版本 https://www.cnblogs.com/nmap/p/10779658.html centos 7 op ...

  4. liunx mkisofs 命令的使用(制作iso)

    参考的博客 http://www.cnblogs.com/darkknightzh/p/8564483.html 有很多时候需要在liunx 环境中将文件打成 iso 所有很多时候就会用到这个命令(m ...

  5. JavaScript监听回车事件

    记录一下,兼容性也考虑到了,原文地址:JavaScript 监听回车事件 JS监听某个输入框 //回车事件绑定 $('#search_input').bind('keyup', function(ev ...

  6. 实现LAMP架构

    LAMP介绍 LAM(M)P: L: linux A: apache (httpd) M: mysql, mariadb M:memcached P: php, perl, python WEB资源类 ...

  7. awk 内置函数的使用

    转自:http://gdcsy.blog.163.com/blog/static/12734360920130241521280/ 一.split 初始化和类型强制        awk的内建函数sp ...

  8. idou老师教你学Istio 26:如何使用Grafana进行可视化监控

    使用Grafana插件进行监控是Istio提供的监控能力之一.Istio提供丰富的监控能力,Grafana插件在Istio对Prometheus支持的基础上,为用户提供基于网页仪表面板的可视化监控效果 ...

  9. 用js刷剑指offer(调整数组顺序使奇数位于偶数前面)

    题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 牛客网链接 js代码 ...

  10. CodeForces 768E SG函数 整数划分 Game of Stones

    一个标准的NIM游戏 加上一条规则:每堆石子对于每个数目的石子只能被取一次 可以SG打表 dp[i][j]表示现在有i个石子 j是可以取的石子数的状压 第i位为1就表示i个石子没被取过 #includ ...