简单学习记录下,flutter的简单的上拉加载下拉刷新
效果图
上代码
class RefreshWidget extends StatefulWidget {
@override
_RefreshState createState() {
return _RefreshState();
}
}
class _RefreshState extends State<RefreshWidget> {
// 用一个key来保存下拉刷新控件RefreshIndicator
GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
// 承载listView的滚动视图
ScrollController _scrollController = ScrollController();
// 数据源
List<String> _dataSource = List<String>();
// 当前加载的页数
int _pageSize = 0;
// 加载数据
void _loadData(int index) {
for (int i=0; i<15; i++) {
_dataSource.add((i+15*index).toString());
}
}
// 下拉刷新
Future<Null> _onRefresh() {
return Future.delayed(Duration(seconds: 2), () {
print("正在刷新...");
_pageSize = 0;
_dataSource.clear();
setState(() {
_loadData(_pageSize);
});
});
}
// 加载更多
Future<Null> _loadMoreData() {
return Future.delayed(Duration(seconds: 1), () {
print("正在加载更多...");
setState(() {
_pageSize++;
_loadData(_pageSize);
});
});
}
// 刷新
showRefreshLoading() {
new Future.delayed(const Duration(seconds: 0), () {
_refreshKey.currentState.show().then((e) {});
return true;
});
}
@override
void initState() {
showRefreshLoading();
_scrollController.addListener(() {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
_loadMoreData();
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return RefreshIndicator(
key: _refreshKey,
onRefresh: _onRefresh,
child: ListView.separated(
controller: _scrollController,
padding: EdgeInsets.all(8.0),
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (buildContext, index) {
return items(context, index);
},
itemCount: _dataSource.isEmpty ? 0 : _dataSource.length+1,
separatorBuilder: (buildContext, index) {
return Divider(
height: 1,
color: Colors.lightGreen,
);
},
),
);
}
// item控件
Widget items(context, index) {
if (index == _dataSource.length) {
return Container(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(
backgroundColor: Theme.of(context).primaryColor,
),
SizedBox(
width: 10.0,
),
Text(
"正在加载",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14.0,
color: Colors.deepPurple
),
)
],
),
)
),
);
}
return Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Text.rich(TextSpan(
children: [
TextSpan(text: "我是第"),
TextSpan(
text: "${_dataSource[index]}",
style: TextStyle(
color: Colors.red,
fontSize: 18.0,
fontWeight: FontWeight.bold
)
),
TextSpan(text: "个")
]
)),
)
);
}
}
这里有段代码
// 刷新
showRefreshLoading() {
new Future.delayed(const Duration(seconds: 0), () {
_refreshKey.currentState.show().then((e) {});
return true;
});
}
_refreshKey.currentState.show()
表示刷新时的头部,他放在一个延时的异步操作中,当时还在考虑为什么放在异步里,直接在initState
里调用不行么,试了一下,报错,错误日志是因为RefreshIndicator
为空,也就是图层还没渲染完成,build方法还没执行完,这里加异步是为了等渲染完成后再进行操作,即使延迟时间为0秒。
另外注意RefreshIndicator
这个Widget,里面有一个onRefresh
属性,他只接收一个Future对象,所以为什么这里下拉刷新,加载更多方法要设置返回值为Future。
还有这里的itemCount
属性为
_dataSource.isEmpty ? 0 : _dataSource.length+1
是当没有数据时只有顶部圆圈存在,当有数据时,除了每条数据占据一行以外,当滑到最下面时,有一个加载widget占据一行。
另外还有flutter_easyrefresh刷新加载这个第三方,改天试试。