my_refresh_list.dart 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import 'package:flutter/cupertino.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:ftrecruiter/comm/utils/dark_theme_util.dart';
  4. /// 封装下拉刷新与加载更多
  5. class MyRefreshListView extends StatefulWidget {
  6. const MyRefreshListView({
  7. Key? key,
  8. required this.itemCount,
  9. required this.itemBuilder,
  10. this.onRefresh,
  11. this.loadMore,
  12. this.hasMore = false,
  13. this.pageSize = 10,
  14. this.padding,
  15. this.itemExtent,
  16. }) : super(key: key);
  17. final RefreshCallback? onRefresh;
  18. final LoadMoreCallback? loadMore;
  19. final int itemCount;
  20. final bool hasMore;
  21. final IndexedWidgetBuilder itemBuilder;
  22. /// 一页的数量,默认为10
  23. final int pageSize;
  24. /// padding属性使用时注意会破坏原有的SafeArea,需要自行计算bottom大小
  25. final EdgeInsetsGeometry? padding;
  26. final double? itemExtent;
  27. @override
  28. _MyRefreshListViewState createState() => _MyRefreshListViewState();
  29. }
  30. typedef RefreshCallback = Future<void> Function();
  31. typedef LoadMoreCallback = Future<void> Function();
  32. class _MyRefreshListViewState extends State<MyRefreshListView> {
  33. /// 是否正在加载数据
  34. bool _isLoading = false;
  35. @override
  36. Widget build(BuildContext context) {
  37. //刷新布局包裹-系统的刷新布局
  38. final Widget child = widget.onRefresh == null
  39. ? ListView.builder(
  40. itemCount: widget.loadMore == null ? widget.itemCount : widget.itemCount + 1,
  41. padding: widget.padding,
  42. itemExtent: widget.itemExtent,
  43. itemBuilder: (BuildContext context, int index) {
  44. /// 不需要加载更多则不需要添加FootView
  45. if (widget.loadMore == null) {
  46. return widget.itemBuilder(context, index);
  47. } else {
  48. return index < widget.itemCount
  49. ? widget.itemBuilder(context, index)
  50. : MoreWidget(widget.itemCount, widget.hasMore, widget.pageSize);
  51. }
  52. },
  53. )
  54. : RefreshIndicator(
  55. onRefresh: widget.onRefresh!,
  56. child: widget.itemCount == 0
  57. ? const SizedBox()
  58. : ListView.builder(
  59. itemCount: widget.loadMore == null ? widget.itemCount : widget.itemCount + 1,
  60. padding: widget.padding,
  61. itemExtent: widget.itemExtent,
  62. itemBuilder: (BuildContext context, int index) {
  63. /// 不需要加载更多则不需要添加FootView
  64. if (widget.loadMore == null) {
  65. return widget.itemBuilder(context, index);
  66. } else {
  67. return index < widget.itemCount
  68. ? widget.itemBuilder(context, index)
  69. : MoreWidget(widget.itemCount, widget.hasMore, widget.pageSize);
  70. }
  71. },
  72. ),
  73. );
  74. //返回真正的布局-监听LoadMore
  75. return SafeArea(
  76. child: NotificationListener<ScrollNotification>(
  77. onNotification: (ScrollNotification note) {
  78. /// 确保是垂直方向滚动,且滑动至底部
  79. if (note.metrics.pixels == note.metrics.maxScrollExtent && note.metrics.axis == Axis.vertical) {
  80. _loadMore();
  81. }
  82. return true;
  83. },
  84. child: child,
  85. ),
  86. );
  87. }
  88. Future<void> _loadMore() async {
  89. if (widget.loadMore == null) {
  90. return;
  91. }
  92. if (_isLoading) {
  93. return;
  94. }
  95. if (!widget.hasMore) {
  96. return;
  97. }
  98. _isLoading = true;
  99. await widget.loadMore?.call();
  100. _isLoading = false;
  101. }
  102. }
  103. //LoadMore-底部加载更多的布局
  104. class MoreWidget extends StatelessWidget {
  105. const MoreWidget(this.itemCount, this.hasMore, this.pageSize, {Key? key}) : super(key: key);
  106. final int itemCount;
  107. final bool hasMore;
  108. final int pageSize;
  109. @override
  110. Widget build(BuildContext context) {
  111. return Container(
  112. height: 50,
  113. alignment:Alignment.center ,
  114. child: Row(
  115. mainAxisAlignment: MainAxisAlignment.center,
  116. children: <Widget>[
  117. if (hasMore) const CupertinoActivityIndicator(),
  118. if (hasMore)
  119. const SizedBox(
  120. width: 5,
  121. ),
  122. // 只有一页的时候,就不显示FooterView了
  123. Text(hasMore ? '正在加载中...' : (itemCount < pageSize ? '' : '没有了呦~'),
  124. style: TextStyle(
  125. fontSize: 14, color: DarkThemeUtil.multiColors(const Color(0x8A000000), darkColor: Colors.white54))),
  126. ],
  127. ),
  128. );
  129. }
  130. }