其实作为菜鸟的我是希望flutter能有一个star很高的插件出来,就不用自己整这东西了。
这里记录一下我的实现逻辑,希望不要误导了小菜鸟,,,
刷新用的是父组件 RefreshIndicator ,加载更多是监听的listview
源码在这
)
1.先写两个组件,一个叫做“加载中…”,一个叫做“—我是有底线的—”
代码片段如下:
Widget _loadMoreWidget() {
return Container(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.only(right: 10),
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2.0,
backgroundColor: Colors.grey,
// value: 0.2,
valueColor: new AlwaysStoppedAnimation(Colors.grey),
),
),
Container(
child: Text("正在加载中...",
style: TextStyle(color: Color(0xff666666), fontSize: 12)),
)
],
),
);
}
Widget _endWidget() {
return Container(
height: 50,
child: Text(
"---我是有底线的---",
style: TextStyle(color: Color(0xff666666), fontSize: 12),
),
);
}
2.准备listview ,用的builder方法,因为这个方法没有横线,
【Flutter listview 上手心得(下拉刷新,上拉加载)】onRefresh:是刷新操作
itemBuilder:需传入listView的组件
itemCount:因为position=0时我是banner组件,postion(1,length-2)是数据,最后一行是“加载更多”或者“底线”
controller:是为了监听滑到最底下
drawer: MyDrawer(),
body: RefreshIndicator(
onRefresh: _getListRefreshData,
child: ListView.builder(
itemBuilder: _mainWidget,
itemCount: _articleList.length == 0 ? 1 : _articleList.length + 2,
controller: _scrollController,
),
)),
3.刷新和加载更多的逻辑,
刷新很简单,传个page=0,就搞定:
//我是刷新网络数据
Future _getListRefreshData() async {
NetService().getArticleList((ArticleModel bean) {
setState(() {
_articleList = bean.data.datas;
});
}, 0);
}
我声明了个bool hasMore来记录是不是有更多,没有更多的话就停止监听,并且显示“我是有底线的”
(1)监听
class HomPageState extends State {
var parentContext;
List _bannerList = new List();
List _articleList = new List();
//分页加载的页数
int _page = 0;
bool _hasMore = true;
ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
//初始加载网络数据
_getBannerData();
_getListData(0);
_scrollController.addListener(() {
if (_hasMore) {
//滑动到底
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_page++;
_getListData(_page);
}
}
});
}
(2) 加载没有更多的逻辑
定的20条,所以刷下来数据小于20条我就认为没有更多了,但是数据还是正常加进去
//我是加载更多
_getListData(int page) async {
NetService().getArticleList((ArticleModel bean) {
if (bean.data.datas.length < 20) {
_hasMore = false;
}
setState(() {
_articleList.addAll(bean.data.datas);
});
}, page);
}
当没有更多了监听就得停下来了:如(1)
当没有更多了,最下面就显示我是底线啦。。。
Widget _mainWidget(BuildContext context, int position) {
//轮播图 --- 列表 --列表的最后一个(“加载更多”,“----底线---”)
if (position == 0) {
return Container(
height: 200,
child: _bannerList.length == 0 ? Text("") : _swiper(),
);
} else if (position == _articleList.length + 1) {
if (_hasMore) {
return _loadMoreWidget();
} else {
return _endWidget();
}
} else {
return _itemWidget(context, position);
}
}
全部代码:
import 'package:flutter/material.dart';
import 'package:wan_flutter/api/net/NetService.dart';
import 'package:wan_flutter/model/ArticleModel.dart';
import 'package:wan_flutter/model/BannerModel.dart';
import 'package:wan_flutter/ui/main/MyDrawer.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:wan_flutter/ui/webview/MyWebViewPage.dart';
class HomePage extends StatefulWidget {
final mContext;
const HomePage({Key key, this.mContext}) : super(key: key);
@override
State createState() => HomPageState();
}class HomPageState extends State {
var parentContext;
List _bannerList = new List();
List _articleList = new List();
//分页加载的页数
int _page = 0;
bool _hasMore = true;
ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
//初始加载网络数据
_getBannerData();
_getListData(0);
_scrollController.addListener(() {
if (_hasMore) {
//滑动到底
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_page++;
_getListData(_page);
}
}
});
}@override
Widget build(BuildContext context) {
parentContext = widget.mContext;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("首页"),
elevation: 0.2,
actions: [
IconButton(
icon: Icon(
Icons.search,
color: Colors.white,
),
onPressed: () {},
)
],
),
drawer: MyDrawer(),
body: RefreshIndicator(
onRefresh: _getListRefreshData,
child: ListView.builder(
itemBuilder: _mainWidget,
itemCount: _articleList.length == 0 ? 1 : _articleList.length + 2,
controller: _scrollController,
),
)),
);
}Widget _mainWidget(BuildContext context, int position) {
if (position == 0) {
return Container(
height: 200,
child: _bannerList.length == 0 ? Text("") : _swiper(),
);
} else if (position == _articleList.length + 1) {
if (_hasMore) {
return _loadMoreWidget();
} else {
return _endWidget();
}
} else {
return _itemWidget(context, position);
}
}Swiper _swiper() {
return Swiper(
autoplay: true,
autoplayDelay: 10000,
scrollDirection: Axis.horizontal,
pagination: SwiperPagination(
builder: DotSwiperPaginationBuilder(
size: 5, //点点没选中时候的大小
activeSize: 8, //点点选中后的大小
color: Colors.white, //点点的颜色
activeColor: Colors.deepOrangeAccent),
alignment: Alignment.bottomRight),
itemCount: _bannerList.length,
itemBuilder: (BuildContext context, int index) {
return Image.network(
_bannerList[index].imagePath,
fit: BoxFit.fill,
);
},
onTap: (index) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyWebViewPage(
title: _bannerList[index].title,
url: _bannerList[index].url)));
},
);
}Widget _itemWidget(BuildContext context, int position) {
return InkWell(
onTap: () {
Navigator.push(
parentContext,
MaterialPageRoute(
builder: (context) => MyWebViewPage(
title: _articleList[position - 1].title,
url: _articleList[position - 1].link)));
},
child: Container(
padding: EdgeInsets.only(left: 20, right: 20, top: 10),
child: Column(
children: [
Container(
child: Row(
children: [
Expanded(
child: Text(
_articleList[position - 1].author.isEmpty
? ""
: _articleList[position - 1].author,
style:
TextStyle(color: Color(0xff666666), fontSize: 12),
textAlign: TextAlign.left,
),
),
Expanded(
child: Text(
_articleList[position - 1].niceDate.isEmpty
? ""
: _articleList[position - 1].niceDate,
style:
TextStyle(color: Color(0xff666666), fontSize: 12),
textAlign: TextAlign.right,
),
)
],
)),
Container(
padding: EdgeInsets.only(top: 10, bottom: 10),
alignment: Alignment.centerLeft,
child: Text(
_articleList[position - 1].title.isEmpty
? ""
: _articleList[position - 1].title,
style: TextStyle(
color: Color(0xff333333),
fontSize: 16,
fontWeight: FontWeight.w700),
textAlign: TextAlign.left,
)),
Container(
alignment: Alignment.bottomLeft,
margin: EdgeInsets.only(bottom: 10),
child: Row(
children: [
Expanded(
child: Text(
_articleList[position - 1].superChapterName.isEmpty
? ""
: _articleList[position - 1].superChapterName,
style:
TextStyle(color: Color(0xff666666), fontSize: 12),
textAlign: TextAlign.left,
),
)
],
),
),
Container(
height: 0.5,
alignment: Alignment.bottomCenter,
child: Divider(
color: Color(0xff00b7ee),
),
)
],
)));
}Widget _loadMoreWidget() {
return Container(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.only(right: 10),
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2.0,
backgroundColor: Colors.grey,
// value: 0.2,
valueColor: new AlwaysStoppedAnimation(Colors.grey),
),
),
Container(
child: Text("正在加载中...",
style: TextStyle(color: Color(0xff666666), fontSize: 12)),
)
],
),
);
}Widget _endWidget() {
return Container(
height: 50,
child: Text(
"---我是有底线的---",
style: TextStyle(color: Color(0xff666666), fontSize: 12),
),
);
}//加载banner网路数据
Future _getBannerData() async {
NetService().getBanner((BannerModel bean) {
if (bean != null && bean.data.length > 0) {
setState(() {
_bannerList = bean.data;
});
}
});
}//我是加载更多
_getListData(int page) async {
NetService().getArticleList((ArticleModel bean) {
if (bean.data.datas.length < 20) {
_hasMore = false;
}
setState(() {
_articleList.addAll(bean.data.datas);
});
}, page);
}
//我是刷新数据
Future _getListRefreshData() async {
NetService().getArticleList((ArticleModel bean) {
setState(() {
_articleList = bean.data.datas;
});
}, 0);
}
}