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

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

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

provide内定义参数

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

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

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

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

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

引入fresh插件

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

  1. import 'package:flutter_easyrefresh/easy_refresh.dart';

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

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

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

再复制首页的footerKey

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

这样key这里就不报错了。

noMoreText用状态 管理里面的值

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

效果展示

loadMore回调函数补充完整

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

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

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

修改为使用addAll的方法

调用我们获取数据的方法

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

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

修正一个错误的地方

上拉刷新的效果

page需要++

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

存在问题

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

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

最终代码:

provide/child_category.dart

  1. import 'package:flutter/material.dart';
  2. import '../model/category.dart';
  3.  
  4. class ChildCategory with ChangeNotifier{
  5. List<BxMallSubDto> childCategoryList=[];
  6. int childIndex=;//子类高亮索引
  7. String categoryId='';//大类ID 白酒的id 默认为4
  8. String subId='';//小类ID
  9. int page=;
  10. String noMoreText='';//显示没有数据的文字
  11. //大类切换逻辑
  12. getChildCategory(List<BxMallSubDto> list,String id){
  13. page=;
  14. noMoreText='';
  15. childIndex=;//每次点击大类,小类的索引都要清空掉
  16. categoryId=id;
  17. BxMallSubDto all=BxMallSubDto();
  18. all.mallCategoryId="";
  19. all.mallCategoryId="";
  20. all.comments="null";
  21. all.mallSubName='全部';
  22. childCategoryList=[all];
  23. //childCategoryList=list;
  24. childCategoryList.addAll(list);
  25. notifyListeners();//监听
  26. }
  27. //改变子类索引,indexs是从哪里来的呢?从我们具体的类中进行传递
  28. changeChildIndex(index,String id){
  29. page=;
  30. noMoreText='';
  31. childIndex=index;//把传递过来的index赋值给我们的childIndex
  32. subId=id;
  33. notifyListeners();//通知
  34. }
  35. //增加Page的方法
  36. addPage(){
  37. page++;
  38. //notifyListeners();//这里不需要通知,因为我们只是page+1了并没有页面数据上的变化
  39. }
  40. //改变noMore的方法
  41. changeNoMore(String text){
  42. noMoreText=text;
  43. notifyListeners();//通知
  44. }
  45. }

provide/category_goods_list.dart

  1. import 'package:flutter/material.dart';
  2. import '../model/categoryGoodsList.dart';
  3.  
  4. class CategoryGoodsListProvide with ChangeNotifier{
  5. List<CategoryListData> goodsList=[];
  6. //点击大类时候更换商品列表
  7. getGoodsList(List<CategoryListData> list){
  8. goodsList=list;
  9. notifyListeners();
  10. }
  11.  
  12. getMoreList(List<CategoryListData> list){
  13. goodsList.addAll(list);
  14. notifyListeners();
  15. }
  16.  
  17. }
  1. import 'package:flutter/material.dart';
  2. import '../service/service_method.dart';
  3. import 'dart:convert';
  4. import '../model/category.dart';
  5. import '../model/categoryGoodsList.dart';
  6. import 'package:flutter_screenutil/flutter_screenutil.dart';
  7. import 'package:provide/provide.dart';
  8. import '../provide/child_category.dart';
  9. import '../provide/category_goods_list.dart';
  10. import 'package:flutter_easyrefresh/easy_refresh.dart';
  11.  
  12. class CategoryPage extends StatefulWidget {
  13. @override
  14. _CategoryPageState createState() => _CategoryPageState();
  15. }
  16.  
  17. class _CategoryPageState extends State<CategoryPage> {
  18. @override
  19. Widget build(BuildContext context) {
  20. //_getCategory();
  21. return Scaffold(
  22. appBar: AppBar(title: Text('商品分类'),),
  23. body: Container(
  24. child: Row(
  25. children: <Widget>[
  26. LeftCategoryNav(),
  27. Column(
  28. children: <Widget>[
  29. RightCategoryNav(),
  30. CategoryGoodsList()
  31. ],
  32. )
  33. ],
  34. ),
  35. ),
  36. );
  37. }
  38.  
  39. }
  40.  
  41. //左侧大类导航
  42. class LeftCategoryNav extends StatefulWidget {
  43. @override
  44. _LeftCategoryNavState createState() => _LeftCategoryNavState();
  45. }
  46.  
  47. class _LeftCategoryNavState extends State<LeftCategoryNav> {
  48. List list=[];
  49. var listIndex=;
  50. @override
  51. void initState() {
  52. super.initState();
  53. _getCategory();//请求接口的数据
  54. _getGoodsList();//参数是可选的默认是4 所以这里可以不用传值
  55. }
  56. @override
  57. Widget build(BuildContext context) {
  58. return Container(
  59. width: ScreenUtil().setWidth(),
  60. decoration: BoxDecoration(
  61. border: Border(
  62. right: BorderSide(width:1.0,color: Colors.black12),//有边框
  63. )
  64. ),
  65. child: ListView.builder(
  66. itemCount: list.length,
  67. itemBuilder: (contex,index){
  68. return _leftInkWell(index);
  69. },
  70. ),
  71. );
  72. }
  73.  
  74. Widget _leftInkWell(int index){
  75. bool isClick=false;
  76. isClick=(index==listIndex)?true:false;
  77. return InkWell(
  78. onTap: (){
  79. setState(() {
  80. listIndex=index;
  81. });
  82. var childList=list[index].bxMallSubDto;//当前大类的子类的列表
  83. var categoryId=list[index].mallCategoryId;//大类的id
  84. Provide.value<ChildCategory>(context).getChildCategory(childList,categoryId);
  85. _getGoodsList(categoryId:categoryId);
  86. },
  87. child: Container(
  88. height: ScreenUtil().setHeight(),
  89. padding: EdgeInsets.only(left:10.0,top:10.0),
  90. decoration: BoxDecoration(
  91. color: isClick?Color.fromRGBO(, , , 1.0): Colors.white,
  92. border: Border(
  93. bottom: BorderSide(width: 1.0,color: Colors.black12)
  94. )
  95. ),
  96. child: Text(
  97. list[index].mallCategoryName,
  98. style: TextStyle(fontSize: ScreenUtil().setSp()),//设置字体大小,为了兼容使用setSp
  99. ),
  100. ),
  101. );
  102. }
  103. void _getCategory() async{
  104. await request('getCategory').then((val){
  105. var data=json.decode(val.toString());
  106. //print(data);
  107. CategoryModel category= CategoryModel.fromJson(data);
  108. setState(() {
  109. list=category.data;
  110. });
  111. Provide.value<ChildCategory>(context).getChildCategory(list[].bxMallSubDto,list[].mallCategoryId);
  112. });
  113. }
  114.  
  115. void _getGoodsList({String categoryId}) {
  116. var data={
  117. 'categoryId':categoryId==null?'':categoryId,//白酒的默认类别
  118. 'categorySubId':"",
  119. 'page':
  120. };
  121. request('getMallGoods',formData: data).then((val){
  122. var data=json.decode(val.toString());
  123. CategoryGoodsListModel goodsList=CategoryGoodsListModel.fromJson(data);//这样就从json'转换成了model类
  124. //print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>:${goodsList.data[0].goodsName}');
  125. // setState(() {
  126. // list=goodsList.data;
  127. // });
  128. Provide.value<CategoryGoodsListProvide>(context).getGoodsList(goodsList.data);
  129. });
  130. }
  131. }
  132.  
  133. class RightCategoryNav extends StatefulWidget {
  134. @override
  135. _RightCategoryNavState createState() => _RightCategoryNavState();
  136. }
  137.  
  138. class _RightCategoryNavState extends State<RightCategoryNav> {
  139. //List list = ['名酒','宝丰','北京二锅头','舍得','五粮液','茅台','散白'];
  140. @override
  141. Widget build(BuildContext context) {
  142. return Provide<ChildCategory>(
  143. builder: (context,child,childCategory){
  144. return Container(
  145. height: ScreenUtil().setHeight(),
  146. width: ScreenUtil().setWidth(),//总的宽度是750 -180
  147. decoration: BoxDecoration(
  148. color: Colors.white,//白色背景
  149. border: Border(
  150. bottom: BorderSide(width: 1.0,color: Colors.black12)//边界线
  151. )
  152. ),
  153. child: ListView.builder(
  154. scrollDirection: Axis.horizontal,
  155. itemCount: childCategory.childCategoryList.length,
  156. itemBuilder: (context,index){
  157. return _rightInkWell(index,childCategory.childCategoryList[index]);
  158. },
  159. ),
  160. );
  161. }
  162. );
  163. }
  164.  
  165. Widget _rightInkWell(int index,BxMallSubDto item){
  166. bool isClick=false;
  167. isClick=(index==Provide.value<ChildCategory>(context).childIndex)?true:false;
  168.  
  169. return InkWell(
  170. onTap: (){
  171. Provide.value<ChildCategory>(context).changeChildIndex(index,item.mallSubId);
  172. _getGoodsList(item.mallSubId);
  173. },//事件留空
  174. child: Container(//什么都加一个container,这样好布局
  175. padding: EdgeInsets.fromLTRB(5.0, 10.0, 5.0, 10.0),//上下是10 左右是5.0
  176. child: Text(
  177. item.mallSubName,
  178. style:TextStyle(
  179. fontSize: ScreenUtil().setSp(),
  180. color: isClick?Colors.pink:Colors.black
  181. ),
  182. ),
  183. ),
  184. );
  185. }
  186. void _getGoodsList(String categorySubId) {
  187. var data={
  188. 'categoryId':Provide.value<ChildCategory>(context).categoryId,//大类ID
  189. 'categorySubId':categorySubId,
  190. 'page':
  191. };
  192. request('getMallGoods',formData: data).then((val){
  193. var data=json.decode(val.toString());
  194. CategoryGoodsListModel goodsList=CategoryGoodsListModel.fromJson(data);//这样就从json'转换成了model类
  195. if(goodsList.data==null){
  196. Provide.value<CategoryGoodsListProvide>(context).getGoodsList([]);
  197. }else{
  198. Provide.value<CategoryGoodsListProvide>(context).getGoodsList(goodsList.data);
  199. }
  200.  
  201. });
  202. }
  203. }
  204.  
  205. //商品列表 ,可以上拉加载
  206. class CategoryGoodsList extends StatefulWidget {
  207. @override
  208. _CategoryGoodsListState createState() => _CategoryGoodsListState();
  209. }
  210.  
  211. class _CategoryGoodsListState extends State<CategoryGoodsList> {
  212. GlobalKey<RefreshFooterState> _footerkey=new GlobalKey<RefreshFooterState>();
  213. var scrollController=new ScrollController();
  214. @override
  215. void initState() {
  216. //_getGoodsList();
  217. super.initState();
  218. }
  219. @override
  220. Widget build(BuildContext context) {
  221. return Provide<CategoryGoodsListProvide>(
  222. builder: (context,child,data){
  223. try {
  224. if(Provide.value<ChildCategory>(context).page==){
  225. //列表位置,放到最上边
  226. scrollController.jumpTo(0.0);
  227. }
  228. } catch (e) {
  229. print('进入页面第一次初始化:${e}');
  230. }
  231. if(data.goodsList.length>){
  232. return Expanded(
  233. child: Container(
  234. width: ScreenUtil().setWidth(),
  235. //height: ScreenUtil().setHeight(974),
  236. child: EasyRefresh(
  237. refreshFooter: ClassicsFooter(
  238. key: _footerkey,
  239. bgColor: Colors.white,//背景颜色
  240. textColor: Colors.pink,//粉红色
  241. moreInfoColor: Colors.white,
  242. showMore: true,
  243. noMoreText: Provide.value<ChildCategory>(context).noMoreText,//具体也不知道到没到底 所以这里直接设置为空就不再显示了
  244. moreInfo: '加载中',
  245. loadReadyText: '上拉加载......',//网上拉 显示的文字
  246. ),
  247. child: ListView.builder(
  248. controller: scrollController,
  249. itemCount: data.goodsList.length,
  250. itemBuilder: (contex,index){
  251. return _listWidget(data.goodsList,index);
  252. },
  253. ),
  254. loadMore: () async{
  255. print('上拉加载更多......');
  256. _getMoreList();
  257. },
  258. )
  259. ),
  260. );
  261. }else{
  262. return Text('暂时没有数据');
  263. }
  264.  
  265. },
  266. );
  267. }
  268.  
  269. void _getMoreList() {
  270. Provide.value<ChildCategory>(context).addPage();
  271. var data={
  272. 'categoryId':Provide.value<ChildCategory>(context).categoryId,//大类ID
  273. 'categorySubId':Provide.value<ChildCategory>(context).subId,
  274. 'page':Provide.value<ChildCategory>(context).page
  275. };
  276. request('getMallGoods',formData: data).then((val){
  277. var data=json.decode(val.toString());
  278. CategoryGoodsListModel goodsList=CategoryGoodsListModel.fromJson(data);//这样就从json'转换成了model类
  279. if(goodsList.data==null){
  280. Provide.value<ChildCategory>(context).changeNoMore('没有更多了');
  281. }else{
  282. Provide.value<CategoryGoodsListProvide>(context).getMoreList(goodsList.data);
  283. }
  284.  
  285. });
  286. }
  287.  
  288. //}
  289.  
  290. Widget _goodsImage(List newList,index){
  291. return Container(
  292. width: ScreenUtil().setWidth(),//设置200的宽度 限制
  293. child: Image.network(newList[index].image),
  294. );
  295. }
  296. Widget _goodsName(List newList,index){
  297. return Container(
  298. padding: EdgeInsets.all(5.0),//上下左右都是5.0的内边距
  299. width: ScreenUtil().setWidth(),//370是一个大约的值
  300. child: Text(
  301. newList[index].goodsName,
  302. maxLines: ,//最多显示2行内容
  303. overflow: TextOverflow.ellipsis,
  304. style: TextStyle(fontSize: ScreenUtil().setSp()),//字体大小
  305. ),
  306. );
  307. }
  308.  
  309. Widget _goodsPrice(List newList,index){
  310. return Container(
  311. margin: EdgeInsets.only(top:20.0),//和上面的外间距
  312. width: ScreenUtil().setWidth(),//370是一个大约的值
  313. child: Row(
  314. children: <Widget>[
  315. Text(
  316. '价格¥${newList[index].presentPrice}',
  317. style: TextStyle(color: Colors.pink,fontSize: ScreenUtil().setSp()),
  318. ),
  319. Text(
  320. '价格¥${newList[index].oriPrice}',
  321. style: TextStyle(
  322. color: Colors.black26,
  323. decoration: TextDecoration.lineThrough
  324. ),//删除线的样式
  325. )
  326. ],
  327. ),
  328. );
  329. }
  330.  
  331. Widget _listWidget(List newList,int index){
  332. return InkWell(
  333. onTap: (){},
  334. child: Container(
  335. padding: EdgeInsets.only(top:5.0,bottom:5.0),
  336. decoration: BoxDecoration(
  337. color: Colors.white,
  338. border: Border(
  339. bottom: BorderSide(width: 1.0,color: Colors.black12)
  340. )
  341. ),
  342. child: Row(
  343. children: <Widget>[
  344. _goodsImage(newList,index),
  345. Column(
  346. children: <Widget>[
  347. _goodsName(newList,index),
  348. _goodsPrice(newList,index)
  349. ],
  350. )
  351. ],
  352. ),
  353. ),
  354. );
  355. }
  356. }

category_page.dart

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

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

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

  2. Flutter移动电商实战 --(35)列表页_上拉加载更多制作

    右侧列表上拉加载配合类别的切换 上拉加载需要一个page参数,当点击大类或者小类的时候,这个page就要变成1 provide内定义参数 首先我们需要定义一个page的变量 下图是我们之前在首页的时候 ...

  3. Flutter实战视频-移动电商-34.列表页_小BUG的修复

    34.列表页_小BUG的修复 当高粱酒的子类没有数据返回的时候就会报错. 解决接口空数据报错的问题 没有数据的时候,给用户一个友好的提示, 我们没有数据的时候还要告诉用户,提示一下他没有数据,在我们的 ...

  4. Flutter实战视频-移动电商-28.列表页_商品列表后台接口调试

    28.列表页_商品列表后台接口调试 主要调试商品列表页的接口 这个接口是最难的因为有大类.小类还有上拉加载 先配置接口 config/service_url.dart //const serviceU ...

  5. Flutter实战视频-移动电商-31.列表页_列表切换交互制作

    31.列表页_列表切换交互制作 博客地址:https://jspang.com/post/FlutterShop.html#toc-c42 点击左侧的大类右边的小类也跟着变化 新建provide 要改 ...

  6. Flutter实战视频-移动电商-33.列表页_子类和商品列表交互效果

    33.列表页_子类和商品列表交互效果 主要实现点击小类下面的列表跟着切换 获取右侧下面的列表信息,即要传递大类的id也要传递小类的,所以需要把左侧的大类的id也要Provide化 可以看下网站上的接口 ...

  7. Flutter实战视频-移动电商-25.列表页_使用Provide控制子类-1

    25.列表页_使用Provide控制子类-1 主要是二级分类的UI布局 1分15秒 生成我们的右侧动态类 定义list变量 开始写里面的子项,把每一个小的写了 再拼成一个大的 这样我们的小类就写完了 ...

  8. Flutter实战视频-移动电商-26.列表页_使用Provide控制子类-2

    26.列表页_使用Provide控制子类-2 主要实现功能,点击一级分类,二级分类跟着变.这里主要用哦我们的provide 新建provide provide文件夹下创建:child_category ...

  9. Flutter实战视频-移动电商-27.列表页_现有Bug修复和完善

    27.列表页_现有Bug修复和完善 小解决小bug 默认右侧的小类没有被加载 数据加载完成后,就list的第一个子对象传递给provide进行赋值,这样右侧的小类就刷新了数据 默认加载了第一个类别 调 ...

随机推荐

  1. Laravel建站05--缓存、时间日期处理包

    缓存 Laravel 给多种缓存系统提供丰富而统一的 API,缓存配置信息位于 config/cache.php,在这个文件中你可以为你的应用程序指定默认的缓存驱动,Laravel 支持当前流行的缓存 ...

  2. [概率dp] hdu 5378 Leader in Tree Land

    题意: 给你一颗以1位根节点的树.我们定义对于每一个子树,节点权值最大的权值记为这个子树的权值,为你将1~n放到这个树里 满足最大权值仅仅有k个的组合数是多少. 思路: 我们能够知道以每一个节点为子树 ...

  3. hessian实战1

    服务端: 1.新建MAVEN HessianServer 项目 2.新建接口 Basic public interface Basic { String hello(String name); Str ...

  4. mysql导入数据库_仅仅用frm向mysql导入表结构

    网上一个连接mysql的jsp代码段,给了数据库的备份文件.可是仅仅有frm, mysql的每张表有三个文件.各自是,*.frm是描写叙述了表的结构.*.MYD保存了表的数据记录.*.MYI则是表的索 ...

  5. mysql 中alter语句中change跟modify的区别

    mysql 中alter语句中change和modify的区别可以使用CHANGE old_col_name column_definition子句对列进行重命名.重命名时,需给定旧的和新的列名称和列 ...

  6. Python中十六进制和字符串的转换(转载)

    调用Python内置int()函数把该字串转为数字.以下为在Python解释器编程环境下的操作示范: 把十六进制的字串转为十进制数字:Python代码>>> print int('f ...

  7. Android Material Design 中文版

    http://www.google.com/design/spec/animation/authentic-motion.html http://www.oschina.net/question/14 ...

  8. 基于docker/虚拟机的esp32远程工作流

    原文:基于docker/虚拟机的esp32远程工作流 工作流框图 背景说明 为什么需要这套工作流--为了满足高效和灵活的开发方式 因为我经常需要在公司和家里切换不同的电脑工作,所以编译环境需要在远程主 ...

  9. android android:duplicateParentState=&quot;true&quot; &quot;false&quot;

    今天要做一个效果.组件RelativeLayout上有两个TextView.这两个TextView具有不同的颜色值,如今要的效果是,当RelativeLayout被点击时,整个item有高亮背景. 同 ...

  10. php 实现简单加入购物车

    今天在练习购物车以及提交订单,写的有点头晕,顺便也整理一下,这个购物车相对来说比较简单,用于短暂存储,并没有存储到数据库, 购物车对于爱网购的人来说简直是熟悉的不能再熟悉了,在写购物车之前,我们首先要 ...