頁面變化的幾種方式:
一、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的內容粘貼過來,
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(), ], ), ); } }