20.首页_火爆专区上拉加载效果

上拉加载的插件比较都差不多。没有一个一枝独秀的

可以自定义酷炫的header和footer

一直在更新

推荐使用这个插件:

https://github.com/xuelongqy/flutter_easyrefresh

添加依赖

首先添加引用我们的插件:

pubspec.yaml。用最新的版本

页面上添加引用

import 'package:flutter_easyrefresh/easy_refresh.dart';

上拉加载我们是要做到我们的主方法里面的。只有做到主方法里面才能做到上拉加载和下拉刷新

这里的代码我们要进行修改。最外层不在使用:SingleChildScrollView

我们最外层就是套的EasyRefresh。因为EasyRefresh有要求 子对象必须是ListView

写上拉加载的方法

原来在这里加载的数据的也注释掉,没有用了。

效果展示

加载完的提示

加载的文字样式和标题的修改

最终效果展示

最终代码:

import 'package:flutter/material.dart';
import '../service/service_method.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'dart:convert';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart'; class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
} class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin{ int page=;
List<Map> hotGoodsList=[];
GlobalKey<RefreshFooterState> _footerkey=new GlobalKey<RefreshFooterState>();
@override
bool get wantKeepAlive => true; @override
void initState() {
super.initState();
//_getHotGoods();
print('');
} String homePageContent='正在获取数据';
@override
Widget build(BuildContext context) {
var formData={'lon':'115.02932','lat':'35.76189'};//传一个经纬度过去,防止恶意下单
return Scaffold(
appBar: AppBar(title: Text('百姓生活+')),
body: FutureBuilder(
future: request('homePageContent',formData:formData),
builder: (context, snapshot) {
if(snapshot.hasData){
var data=json.decode(snapshot.data.toString());
List<Map> swiper=(data['data']['slides'] as List).cast();
List<Map> navigatorList=(data['data']['category'] as List).cast();
String adPicture=data['data']['advertesPicture']['PICTURE_ADDRESS'];
String leaderImage=data['data']['shopInfo']['leaderImage'];
String leaderPhone=data['data']['shopInfo']['leaderPhone'];
List<Map> recommendList=(data['data']['recommend'] as List).cast();
String floor1Title=data['data']['floor1Pic']['PICTURE_ADDRESS'];
String floor2Title=data['data']['floor2Pic']['PICTURE_ADDRESS'];
String floor3Title=data['data']['floor3Pic']['PICTURE_ADDRESS'];
List<Map> floor1=(data['data']['floor1'] as List).cast();
List<Map> floor2=(data['data']['floor2'] as List).cast();
List<Map> floor3=(data['data']['floor3'] as List).cast(); return EasyRefresh(
refreshFooter: ClassicsFooter(
key: _footerkey,
bgColor: Colors.white,//背景颜色
textColor: Colors.pink,//粉红色
moreInfoColor: Colors.white,
showMore: true,
noMoreText: '',//具体也不知道到没到底 所以这里直接设置为空就不再显示了
moreInfo: '加载中',
loadReadyText: '上拉加载......',//网上拉 显示的文字
),
child: ListView(
children: <Widget>[
SwiperDiy(swiperDateList: swiper),
TopNavigator(navigatorList:navigatorList ,),
AdBanner(adPicture:adPicture),
LeaderPhone(leaderImage: leaderImage,leaderPhone: leaderPhone,),
Recommend(recommendList:recommendList),
FloorTitle(picture_address: floor1Title,),//楼层1的标题图片
FloorContent(floorGoodsList: floor1),
FloorTitle(picture_address: floor2Title,),//楼层1的标题图片
FloorContent(floorGoodsList: floor2),
FloorTitle(picture_address: floor3Title,),//楼层1的标题图片
FloorContent(floorGoodsList: floor3),
_hotGoods()
],
),
loadMore: () async {
print('开始加载更多....');
var formData={'page',page};
await request('homePageBelowConten',formData:formData).then((val){
var data=json.decode(val.toString());
List<Map> newGoodsList=(data['data'] as List).cast();
//把新的列表加到老的列表里面
setState(() {
hotGoodsList.addAll(newGoodsList);
page++;
});
});
},
);
}else{
return Center(child: Text('加载中....'));
}
},
),
);
}
//获取热销商品的数据
// void _getHotGoods(){
// var formData={'page',page};
// request('homePageBelowConten',formData:formData).then((val){
// var data=json.decode(val.toString());
// List<Map> newGoodsList=(data['data'] as List).cast();
// //把新的列表加到老的列表里面
// setState(() {
// hotGoodsList.addAll(newGoodsList);
// page++;
// });
// });
// }
//火爆专区的标题
Widget hotTitle = Container(
margin: EdgeInsets.only(top:10.0),//上边距
alignment: Alignment.center,//居中对齐
color: Colors.transparent,
padding: EdgeInsets.all(5.0),
child: Text('火爆专区'),
); Widget _wrapList(){
if(hotGoodsList.length!=){
List<Widget> listWidget=hotGoodsList.map((val){
return InkWell(
onTap: (){},
child: Container(
width: ScreenUtil().setWidth(),
color: Colors.white,
padding: EdgeInsets.all(5.0),//内边距
margin: EdgeInsets.only(bottom: 3.0),
child: Column(
children: <Widget>[
Image.network(val['image'],width: ScreenUtil().setWidth(),),//设置宽度防止超出边界
Text(
val['name'],
maxLines: ,//只有一行
overflow: TextOverflow.ellipsis,//超出显示省略号的形式
style: TextStyle(color: Colors.pink,fontSize: ScreenUtil().setSp()),
),
Row(
children: <Widget>[
Text('¥${val['mallPrice']}'),//商城价格
Text(
'¥${val['price']}',
style: TextStyle(color: Colors.black26,decoration: TextDecoration.lineThrough),//加上删除线的价格
)
],
)
],
),
),
);
}).toList();
return Wrap(
spacing: ,//每一行显示两列
children: listWidget,
);
}else{
return Text('');
}
} //组合火爆专区的标题和列表
Widget _hotGoods(){
return Container(
child: Column(
children: <Widget>[
hotTitle,
_wrapList()
],
),
);
} }
//首页轮播插件
class SwiperDiy extends StatelessWidget {
final List swiperDateList;
//构造函数
SwiperDiy({this.swiperDateList}); @override
Widget build(BuildContext context) { // print('设备的像素密度:${ScreenUtil.pixelRatio}');
// print('设备的高:${ScreenUtil.screenWidth}');
// print('设备的宽:${ScreenUtil.screenHeight}'); return Container(
height: ScreenUtil().setHeight(),//
width:ScreenUtil().setWidth(),
child: Swiper(
itemBuilder: (BuildContext context,int index){
return Image.network("${swiperDateList[index]['image']}",fit: BoxFit.fill,);
},
itemCount: swiperDateList.length,
pagination: SwiperPagination(),
autoplay: true,
),
);
}
} class TopNavigator extends StatelessWidget {
final List navigatorList; TopNavigator({Key key, this.navigatorList}) : super(key: key); Widget _gridViewItemUI(BuildContext context,item){
return InkWell(
onTap: (){print('点击了导航');},
child: Column(
children: <Widget>[
Image.network(item['image'],width: ScreenUtil().setWidth()),
Text(item['mallCategoryName'])
],
),
);
}
@override
Widget build(BuildContext context) {
if(this.navigatorList.length>){
this.navigatorList.removeRange(,this.navigatorList.length);//从第十个截取,后面都截取掉
}
return Container(
height: ScreenUtil().setHeight(),//只是自己大概预估的一个高度,后续可以再调整
padding: EdgeInsets.all(3.0),//为了不让它切着屏幕的边缘,我们给它一个padding
child: GridView.count(
crossAxisCount: ,//每行显示5个元素
padding: EdgeInsets.all(5.0),//每一项都设置一个padding,这样他就不挨着了。
children: navigatorList.map((item){
return _gridViewItemUI(context,item);
}).toList(),
),
);
}
} class AdBanner extends StatelessWidget {
final String adPicture; AdBanner({Key key, this.adPicture}) : super(key: key); @override
Widget build(BuildContext context) {
return Container(
child: Image.network(adPicture),
);
}
} //店长电话模块
class LeaderPhone extends StatelessWidget {
final String leaderImage;//店长图片
final String leaderPhone;//店长电话 LeaderPhone({Key key, this.leaderImage,this.leaderPhone}) : super(key: key); @override
Widget build(BuildContext context) {
return Container(
child: InkWell(
onTap: _launchURL,
child: Image.network(leaderImage),
),
);
} void _launchURL() async {
String url = 'tel:'+leaderPhone;
//String url = 'http://jspang.com';
if(await canLaunch(url)){
await launch(url);
}else{
throw 'url不能进行访问,异常';
}
}
} //商品推荐
class Recommend extends StatelessWidget {
final List recommendList; Recommend({Key key, this.recommendList}) : super(key: key); //商品标题
Widget _titleWidget(){
return Container(
alignment: Alignment.centerLeft,//局长靠左对齐
padding: EdgeInsets.fromLTRB(10.0, 2.0, , 5.0),//左上右下
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(width: 0.5,color: Colors.black12) //设置底部的bottom的边框,Black12是浅灰色
),
),
child: Text(
'商品推荐',
style:TextStyle(color: Colors.pink)
),
);
}
//商品单独项方法
Widget _item(index){
return InkWell(
onTap: (){},//点击事件先留空
child: Container(
height: ScreenUtil().setHeight(),//兼容性的高度 用了ScreenUtil
width: ScreenUtil().setWidth(),//750除以3所以是250
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
left: BorderSide(width: ,color: Colors.black12)//右侧的 边线的样式 宽度和 颜色
)
),
child: Column(
children: <Widget>[
Image.network(recommendList[index]['image']),
Text('¥${recommendList[index]['mallPrice']}'),
Text(
'¥${recommendList[index]['price']}',
style: TextStyle(
decoration: TextDecoration.lineThrough,//删除线的样式
color: Colors.grey//浅灰色
),
),
],
),
),
);
}
//横向列表方法
Widget _recommendList(){
return Container(
height: ScreenUtil().setHeight(),
child: ListView.builder(
scrollDirection: Axis.horizontal,//横向的
itemCount: recommendList.length,
itemBuilder: (context,index){
return _item(index);
},
),
);
} @override
Widget build(BuildContext context) {
return Container(
height: ScreenUtil().setHeight(),//列表已经设置为330了因为还有上面标题,所以要比330高,这里先设置为380
margin: EdgeInsets.only(top: 10.0),
child: Column(
children: <Widget>[
_titleWidget(),
_recommendList()
],
),
);
}
} //楼层标题
class FloorTitle extends StatelessWidget {
final String picture_address; FloorTitle({Key key, this.picture_address}) : super(key: key); @override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
child: Image.network(picture_address),
);
}
} //楼层商品列表
class FloorContent extends StatelessWidget {
final List floorGoodsList; FloorContent({Key key, this.floorGoodsList}) : super(key: key); @override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
_firstRow(),
_otherGoods()
],
),
);
} Widget _firstRow(){
return Row(
children: <Widget>[
_goodsItem(floorGoodsList[]),
Column(
children: <Widget>[
_goodsItem(floorGoodsList[]),
_goodsItem(floorGoodsList[])
],
)
],
);
}
Widget _otherGoods(){
return Row(
children: <Widget>[
_goodsItem(floorGoodsList[]),
_goodsItem(floorGoodsList[])
],
);
}
Widget _goodsItem(Map goods){
return Container(
width: ScreenUtil().setWidth(),
child: InkWell(
onTap: (){print('点击了楼层商品');},
child: Image.network(goods['image']),
),
);
}
}

home_page.dart

Flutter实战视频-移动电商-20.首页_火爆专区上拉加载效果的更多相关文章

  1. Flutter实战视频-移动电商-18.首页_火爆专区后台接口调试

    18.首页_火爆专区后台接口调试 楼层结束之后有个火爆专区.到地图有个上拉加载的效果 lib/config/service_url.dart 首先找到我们的接口配置文件,增加接口的配置 lib/ser ...

  2. Flutter实战视频-移动电商-19.首页_火爆专区界面布局编写

    19.首页_火爆专区界面布局编写 看一下图片的效果 一个标题栏,下面是多行两列.里面可以用column布局,外面用Warp流式布局 有得小伙伴说这里可以用网格布局,网格布局的话还是有一定的效率问题.这 ...

  3. Flutter实战视频-移动电商-09.首页_项目结构建立和获取数据

    09.首页_项目结构建立和获取数据 在config下创建service_url.dart 用来配置我们后端接口的配置文件 一个变量存 接口地址,一个接口方法地址 所有后天请求数据的方法都放在这个文件夹 ...

  4. Flutter实战视频-移动电商-11.首页_屏幕适配方案讲解

    11.首页_屏幕适配方案讲解 国人写的屏幕适配插件: https://github.com/OpenFlutter/flutter_screenutil 最新版本是0.5.1 在pubspec.yam ...

  5. Flutter实战视频-移动电商-13.首页_广告Banner组件制作

    13.首页_广告Banner组件制作 主要是做这个小广告条. 其实就是读取一个图片做一个widget放到这里 使用stlessW快速生成 定义一个变量存放图片的url地址: 这样我们的广告条就写完了 ...

  6. Flutter实战视频-移动电商-15.首页_商品推荐模块编写

    15.首页_商品推荐模块编写 商品推荐,我们做成可以横向滚动的 分析: 上面是标题,下面是ListView,里面是一个Column, column分三层,第一是图片,第二是价格,第三是市场价格 小细节 ...

  7. Flutter实战视频-移动电商-17.首页_楼层组件的编写技巧

    17.首页_楼层组件的编写技巧 博客地址: https://jspang.com/post/FlutterShop.html#toc-b50 楼层的效果: 标题 stlessW快速生成: 接收一个St ...

  8. Flutter实战视频-移动电商-16.补充_保持页面状态

    16.补充_保持页面状态 修正一个地方: 设置了item的高度为380 横向列表为380.最终build的高度也增加了50为430. 增加了上面的高度以后,下面那个横线划掉的价格可以显示出来了. 但是 ...

  9. Flutter实战视频-移动电商-10.首页_FlutterSwiper轮播效果制作

    10.首页_FlutterSwiper轮播效果制作 博客地址: https://jspang.com/post/FlutterShop.html#toc-5c2 flutter_swiper http ...

随机推荐

  1. systemd、upstart和system V

    http://blog.csdn.net/kumu_linux/article/details/7653802  systemd是Linux下的一种init软件,由Lennart Poettering ...

  2. VM不能ping通www.baidu.com的问题【NAT】 更新了【桥接模式】

    NAT模式 1.为NAT设置子网及掩码等信息 点击VMWare菜单栏“编辑” —> 虚拟网络编辑器 [下图第一张图]—> 选中VMnet8(当然这个看自己的设备后缀是多少了,只要外部连接方 ...

  3. kubernetes调度之资源耗尽处理配置

    系列目录 本篇将介绍如何使用kubelet处理资源耗尽的情况 当可用的计算机资源非常低的时候,kubelet仍然要保证节点的稳定性.当处理不可压缩的计算机资源(比如内存或磁盘空间)时,这尤其重要,当这 ...

  4. bitmap进行个数统计

    昨天看了编程珠玑第一章的内容, 发现bitmap对于统计某一个范围内的整数个数效率很高, 就自己实现了一下: 这是原始的bitmap, 用于统计0~maxSize是否出现, 也可以用于排序 publi ...

  5. [转]JavaScript

    javascript 1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <table border on ...

  6. windows命令大全(转载)

    winver---------检查Windows版本 wmimgmt.msc打开Windows管理体系结构(wmi) wupdmgrWindows更新程序 w脚本Windows脚本宿主设置 write ...

  7. 【BZOJ2729】[HNOI2012]排队 组合数

    [BZOJ2729][HNOI2012]排队 Description 某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检.他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那 ...

  8. Error: EACCES: permission denied, mkdir '/root/.nvm/versions/node/......

    当我执行npm install -g node-inspector的时候报错. 所以就去网上搜索了一下答案. 有这么几种答案.请看完再执行相关命令 有说需要在前面加上sudo命令的. 不能解决我出现的 ...

  9. HDOJ 4689 Derangement DP

    DP具体解释见: http://blog.csdn.net/liguan1/article/details/10468139 Derangement Time Limit: 7000/7000 MS ...

  10. 初学php html javascript后小总结

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/c3568/article/details/30474015 转载请注明出处:http://blog. ...