my_refresh_list.dart 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import 'package:flutter/cupertino.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:liftmanager/res/resources.dart';
  4. import 'package:liftmanager/utils/theme_utils.dart';
  5. import 'package:liftmanager/widgets/state_layout.dart';
  6. /// 封装下拉刷新与加载更多
  7. class MyListView extends StatefulWidget {
  8. const MyListView({
  9. Key key,
  10. @required this.itemCount,
  11. @required this.itemBuilder,
  12. @required this.onRefresh,
  13. this.loadMore,
  14. this.hasMore : false,
  15. this.stateType : StateType.empty,
  16. this.pageSize : 10,
  17. this.padding,
  18. this.itemExtent,
  19. }): super(key: key);
  20. final RefreshCallback onRefresh;
  21. final LoadMoreCallback loadMore;
  22. final int itemCount;
  23. final bool hasMore;
  24. final IndexedWidgetBuilder itemBuilder;
  25. final StateType stateType;
  26. /// 一页的数量,默认为10
  27. final int pageSize;
  28. final EdgeInsetsGeometry padding;
  29. final double itemExtent;
  30. @override
  31. _MyListViewState createState() => _MyListViewState();
  32. }
  33. typedef RefreshCallback = Future<void> Function();
  34. typedef LoadMoreCallback = Future<void> Function();
  35. class _MyListViewState extends State<MyListView> {
  36. /// 是否正在加载数据
  37. bool _isLoading = false;
  38. @override
  39. Widget build(BuildContext context) {
  40. return SafeArea(
  41. child: NotificationListener(
  42. onNotification: (ScrollNotification note){
  43. /// 确保是垂直方向滚动,且滑动至底部
  44. if (note.metrics.pixels == note.metrics.maxScrollExtent && note.metrics.axis == Axis.vertical){
  45. _loadMore();
  46. }
  47. return true;
  48. },
  49. child: RefreshIndicator(
  50. onRefresh: widget.onRefresh,
  51. child: widget.itemCount == 0 ? StateLayout(type: widget.stateType) : ListView.builder(
  52. shrinkWrap: true,
  53. itemCount: widget.loadMore == null ? widget.itemCount : widget.itemCount + 1,
  54. padding: widget.padding,
  55. itemExtent: widget.itemExtent,
  56. itemBuilder: (BuildContext context, int index){
  57. /// 不需要加载更多则不需要添加FootView
  58. if (widget.loadMore == null){
  59. return widget.itemBuilder(context, index);
  60. }else{
  61. return index < widget.itemCount ? widget.itemBuilder(context, index) : MoreWidget(widget.itemCount, widget.hasMore, widget.pageSize);
  62. }
  63. }
  64. )
  65. ),
  66. ),
  67. );
  68. }
  69. Future _loadMore() async {
  70. if (widget.loadMore == null){
  71. return;
  72. }
  73. if (_isLoading) {
  74. return;
  75. }
  76. if (!widget.hasMore){
  77. return;
  78. }
  79. _isLoading = true;
  80. await widget.loadMore();
  81. _isLoading = false;
  82. }
  83. }
  84. class MoreWidget extends StatelessWidget {
  85. const MoreWidget(this.itemCount, this.hasMore, this.pageSize);
  86. final int itemCount;
  87. final bool hasMore;
  88. final int pageSize;
  89. @override
  90. Widget build(BuildContext context) {
  91. final style = const TextStyle(color: Color(0x8A000000));
  92. return Padding(
  93. padding: const EdgeInsets.symmetric(vertical: 10.0),
  94. child: Row(
  95. mainAxisAlignment: MainAxisAlignment.center,
  96. crossAxisAlignment: CrossAxisAlignment.center,
  97. children: <Widget>[
  98. hasMore ? const CupertinoActivityIndicator() : Gaps.empty,
  99. hasMore ? Gaps.hGap5 : Gaps.empty,
  100. /// 只有一页的时候,就不显示FooterView了
  101. Text(hasMore ? '正在加载中...' : (itemCount < pageSize ? '' : '没有了呦~'), style: style),
  102. ],
  103. ),
  104. );
  105. }
  106. }