页面变化的几种方式:
一、StatefulWidget的setState形式
先声明两个变量。
int page = 1; List<Map> list = [];
写了一个方法,获取数据:
void _getHotGoods(){ var formData = {'page':page}; request('post', 'homePageBelowConten',formData: formData).then((val){ var data = json.decode(val.toString()); List<Map> newList = (data['data'] as List).cast(); setState(() { list.addAll(newList); //新的列表加到老的列表之上 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(list.length != 0){ List<Widget> listWidget = list.map((val){ //把Map类型的List包装成Widget,再放回List里,并赋值给流式布局 return InkWell( onTap: (){}, child: Container( width: ScreenUtil().setWidth(372), 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(370)), Text( val['name'], maxLines: 1, overflow:TextOverflow.ellipsis, style:TextStyle(color:Colors.blueGrey,fontSize:ScreenUtil().setSp(26)), ), Row( children: <Widget>[ Text('¥${val['mallPrice']}'), Text( '¥${val['price']}', style: TextStyle(color: Colors.black26,decoration: TextDecoration.lineThrough), ) ], ), ], ), ), ); }).toList(); //把Map类型的List包装成Widget,再放回List里,并赋值给流式布局 return Wrap( //返回流式布局 spacing: 2, //每行2列 children: listWidget, ); }else{ return Text(''); //没有数据时返回空 } }
组合在一起:
//火爆专区组合 Widget _hotGoods(){ return Container( child: Column( children: <Widget>[ hotTitle, _wrapList(), ], ), ); }
完整代码:
import 'package:flutter/material.dart'; import '../service/service_method.dart'; import 'dart:convert'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class CategoryPage extends StatefulWidget { _CategoryPageState createState() => _CategoryPageState(); } class _CategoryPageState extends State<CategoryPage> { int page = 1; List<Map> list = []; @override void initState() { super.initState(); _getHotGoods(); //火爆专区获取值 } @override Widget build(BuildContext context) { return SingleChildScrollView( child:Column( children: <Widget>[ _hotGoods(), ], ), ); } //火爆商品接口 void _getHotGoods(){ var formData = {'page':page}; //Map类型 request('post', 'homePageBelowConten',formData: formData).then((val){ var data = json.decode(val.toString()); List<Map> newList = (data['data'] as List).cast(); setState(() { list.addAll(newList); //新的列表加到老的列表之上 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(list.length != 0){ List<Widget> listWidget = list.map((val){ //Map循环的形式:把Map类型的List包装成Widget,再放回List里,并赋值给流式布局 return InkWell( onTap: (){}, child: Container( width: ScreenUtil().setWidth(372), 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(370)), Text( val['name'], maxLines: 1, overflow:TextOverflow.ellipsis, style:TextStyle(color:Colors.blueGrey,fontSize:ScreenUtil().setSp(26)), ), Row( children: <Widget>[ Text('¥${val['mallPrice']}'), Text( '¥${val['price']}', style: TextStyle(color: Colors.black26,decoration: TextDecoration.lineThrough), ) ], ), ], ), ), ); }).toList(); //Map循环的形式:把Map类型的List包装成Widget,再放回List里,并赋值给流式布局 return Wrap( //返回流式布局 spacing: 2, //每行2列 children: listWidget, ); }else{ return Text(''); //没有数据时返回空 } } //火爆专区组合 Widget _hotGoods(){ return Container( child: Column( children: <Widget>[ hotTitle, _wrapList(), ], ), ); } }
flutter_easyrefresh插件:
EasyRefresh很容易就能在Flutter应用上实现下拉刷新以及上拉加载操作,它支持几乎所有的Flutter控件,但前提是需要包裹成ScrollView。它的功能与Android的SmartRefreshLayout很相似,同样也吸取了很多三方库的优点。EasyRefresh中集成了多种风格的Header和Footer,但是它并没有局限性,你可以很轻松的自定义。使用Flutter强大的动画,甚至随便一个简单的控件也可以完成。EasyRefresh的目标是为Flutter打造一个强大,稳定,成熟的下拉刷新框架。
github:https://github.com/xuelongqy/flutter_easyrefresh
flutter_easyrefresh优点:
- 能够自定义酷炫的Header和Footer,也就是上拉和下拉的效果。
- 更新及时,不断在完善,录课截至时已经是v1.2.7版本了。
- 有一个辅导群,虽然文档不太完善,但是有辅导群和详细的案例。
- 回掉方法简单,这个具体可以看下面的例子。
引入依赖
直接在pubspec.yaml
中的dependencies
中进行引入,主要要用最新版本,文章中的版本不一定是最新版本。
flutter_easyrefresh: ^1.2.7
引入后,在要使用的页面用import
引入package
,代码如下:
import 'package:flutter_easyrefresh/easy_refresh.dart';
制作上拉加载效果
使用这个插件,要求我们必须是一个ListView,所以我们要改造以前的代码,SingleChildScrollView改造成ListView。并添加loadMore,把_getHotGoods的内容粘贴过来,
_getHotGoods();就可以注掉了。
return EasyRefresh( child:ListView( children: <Widget>[ _hotGoods(), ], ), loadMore: () async{ var formData = {'page':page}; //Map类型 await request('post', 'homePageBelowConten',formData: formData).then((val){ var data = json.decode(val.toString()); List<Map> newList = (data['data'] as List).cast(); setState(() { list.addAll(newList); //新的列表加到老的列表之上 page ++; }); }); }, );
现在运行已经可以看到效果了,不过还需要修改下。
自定义上拉加载效果
因为它自带的样式是蓝色的,与我们的界面不太相符,所以我们改造一下,它的底部上拉刷新效果。如果你有兴趣做出更炫酷的效果,可以自行查看一下Github,学习一下。
refreshFooter:ClassicsFooter( //自定义上拉加载效果 key:_footerKey, bgColor:Colors.white, textColor: Colors.blueGrey, moreInfoColor: Colors.blueGrey, showMore: true, noMoreText: '', moreInfo: '加载中', //加载时显示的文字 loadReadyText: '上拉加载...', //准备时显示的文字 ),
还要在上面定义Key:
GlobalKey<RefreshFooterState> _footerKey = new GlobalKey<RefreshFooterState>(); //定义key
完整代码:
import 'package:flutter/material.dart'; import '../service/service_method.dart'; import 'dart:convert'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; class CategoryPage extends StatefulWidget { _CategoryPageState createState() => _CategoryPageState(); } class _CategoryPageState extends State<CategoryPage> { int page = 1; List<Map> list = []; GlobalKey<RefreshFooterState> _footerKey = new GlobalKey<RefreshFooterState>(); //定义key @override void initState() { super.initState(); //_getHotGoods(); //火爆专区获取值 } @override Widget build(BuildContext context) { return EasyRefresh( refreshFooter:ClassicsFooter( //自定义上拉加载效果 key:_footerKey, bgColor:Colors.white, textColor: Colors.blueGrey, moreInfoColor: Colors.blueGrey, showMore: true, noMoreText: '', moreInfo: '加载中', //加载时显示的文字 loadReadyText: '上拉加载...', //准备时显示的文字 ), child:ListView( children: <Widget>[ _hotGoods(), ], ), loadMore: () async{ var formData = {'page':page}; //Map类型 await request('post', 'homePageBelowConten',formData: formData).then((val){ var data = json.decode(val.toString()); List<Map> newList = (data['data'] as List).cast(); setState(() { list.addAll(newList); //新的列表加到老的列表之上 page ++; }); }); }, ); } //火爆商品接口 // void _getHotGoods(){ // var formData = {'page':page}; //Map类型 // request('post', 'homePageBelowConten',formData: formData).then((val){ // var data = json.decode(val.toString()); // List<Map> newList = (data['data'] as List).cast(); // setState(() { // list.addAll(newList); //新的列表加到老的列表之上 // 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(list.length != 0){ List<Widget> listWidget = list.map((val){ //Map循环的形式:把Map类型的List包装成Widget类型,再放回List里,并赋值给流式布局 return InkWell( onTap: (){}, child: Container( width: ScreenUtil().setWidth(372), 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(370)), Text( val['name'], maxLines: 1, overflow:TextOverflow.ellipsis, style:TextStyle(color:Colors.blueGrey,fontSize:ScreenUtil().setSp(26)), ), Row( children: <Widget>[ Text('¥${val['mallPrice']}'), Text( '¥${val['price']}', style: TextStyle(color: Colors.black26,decoration: TextDecoration.lineThrough), ) ], ), ], ), ), ); }).toList(); //Map循环的形式:把Map类型的List包装成Widget类型,再放回List里,并赋值给流式布局 return Wrap( //返回流式布局 spacing: 2, //每行2列 children: listWidget, ); }else{ return Text(''); //没有数据时返回空 } } //火爆专区组合 Widget _hotGoods(){ return Container( child: Column( children: <Widget>[ hotTitle, _wrapList(), ], ), ); } }