https://pub.dev/packages/flutter_easyrefresh
中文说明:https://github.com/xuelongqy/flutter_easyrefresh/blob/v2/README.md

正如名字一样,EasyRefresh很容易就能在Flutter应用上实现下拉刷新以及上拉加载操作,它支持几乎所有的Flutter控件。它的功能与Android的SmartRefreshLayout很相似,同样也吸取了很多三方库的优点。EasyRefresh中集成了多种风格的Header和Footer,但是它并没有局限性,你可以很轻松的自定义。使用Flutter强大的动画,甚至随便一个简单的控件也可以完成。EasyRefresh的目标是为Flutter打造一个强大,稳定,成熟的下拉刷新框架。

依赖
  1. dependencies:
  2. flutter_easyrefresh: ^2.1.7

导入
  1. import 'package:flutter_easyrefresh/bezier_circle_header.dart';
  2. import 'package:flutter_easyrefresh/bezier_hour_glass_header.dart';
  3. import 'package:flutter_easyrefresh/phoenix_footer.dart';
  4. import 'package:flutter_easyrefresh/taurus_header.dart';
  5. import 'package:flutter_easyrefresh/phoenix_header.dart';
  6. import 'package:flutter_easyrefresh/easy_refresh.dart';
  7. import 'package:flutter_easyrefresh/taurus_footer.dart';
  8. import 'package:flutter_easyrefresh/material_header.dart';
  9. import 'package:flutter_easyrefresh/delivery_header.dart';
  10. import 'package:flutter_easyrefresh/material_footer.dart';
  11. import 'package:flutter_easyrefresh/ball_pulse_header.dart';
  12. import 'package:flutter_easyrefresh/bezier_bounce_footer.dart';
  13. import 'package:flutter_easyrefresh/ball_pulse_footer.dart';

在布局文件中添加 EasyreFresh
  1. import 'package:flutter_easyrefresh/easy_refresh.dart';
  2. //....
  3. // 方式一
  4. EasyRefresh(
  5. child: ScrollView(),
  6. onRefresh: () async{
  7. ....
  8. },
  9. onLoad: () async {
  10. ....
  11. },
  12. )
  13. // 方式二
  14. EasyRefresh.custom(
  15. slivers: <Widget>[],
  16. onRefresh: () async{
  17. ....
  18. },
  19. onLoad: () async {
  20. ....
  21. },
  22. )
  23. // 方式三
  24. EasyRefresh.builder(
  25. builder: (context, physics, header, footer) {
  26. return CustomScrollView(
  27. physics: physics,
  28. slivers: <Widget>[
  29. ...
  30. header,
  31. ...
  32. footer,
  33. ],
  34. );
  35. }
  36. onRefresh: () async{
  37. ....
  38. },
  39. onLoad: () async {
  40. ....
  41. },
  42. )

触发刷新和加载动作
  1. EasyRefreshController _controller = EasyRefreshController();
  2. ....
  3. EasyRefresh(
  4. controller: _controller,
  5. ....
  6. );
  7. ....
  8. _controller.callRefresh();
  9. _controller.callLoad();

控制加载和刷新完成
  1. EasyRefreshController _controller = EasyRefreshController();
  2. ....
  3. EasyRefresh(
  4. enableControlFinishRefresh: true,
  5. enableControlFinishLoad: true,
  6. ....
  7. );
  8. ....
  9. _controller.finishRefresh(success: true);
  10. _controller.finishLoad(success true, noMore: false);

使用指定的 Header 和 Footer
  1. import 'package:flutter_easyrefresh/easy_refresh.dart';
  2. import 'package:flutter_easyrefresh/material_header.dart';
  3. import 'package:flutter_easyrefresh/material_footer.dart';
  4. ....
  5. new EasyRefresh(
  6. header: MaterialHeader(),
  7. footer: MaterialFooter(),
  8. child: ScrollView(),
  9. ....
  10. )

添加国际化支持

不提供自带国际化支持,请自行设置ClassicalHeader和ClassicalFooter中需要展示的文字。

ClassicalHeader API

  1. EasyRefresh(
  2. header: ClassicalHeader(
  3. double extent = 60.0,
  4. double triggerDistance = 70.0,
  5. bool float = false, //Header 浮动(Header显示在列表之上)
  6. Duration completeDuration = const Duration(seconds: 1),
  7. bool enableInfiniteRefresh = false, //是否开启无限加载
  8. bool enableHapticFeedback = true, //是否触发震动反馈
  9. bool overScroll = true,
  10. this.key,
  11. this.alignment, //对齐
  12. this.refreshText, //提示刷新文字(下拉刷新)
  13. this.refreshReadyText, //准备刷新文字(释放刷新)
  14. this.refreshingText, //正在刷新文字(刷新中)
  15. this.refreshedText, //刷新完成文字(刷新完成)
  16. this.refreshFailedText, //刷新失败文字
  17. this.noMoreText, //没有更多文字
  18. this.showInfo: true, //是否显示额外信息(默认为时间)
  19. this.infoText, //额外信息
  20. this.bgColor: Colors.transparent, //背景颜色
  21. this.textColor: Colors.black, //字体颜色
  22. this.infoColor: Colors.teal, //额外信息字体颜色
  23. ),
  24. ),

ClassicalFooter API

  1. footer: ClassicalFooter({
  2. double extent = 60.0,
  3. double triggerDistance = 70.0,
  4. bool float = false,
  5. Duration completeDuration = const Duration(seconds: 1),
  6. bool enableInfiniteLoad = true, //是否开启无限加载
  7. bool enableHapticFeedback = true, //是否触发震动反馈
  8. bool overScroll = false, //上拉到底部时,是否继续允许往上拖拽页面(是否允许超出滚动区域)
  9. bool safeArea = true,
  10. EdgeInsets padding,
  11. this.key,
  12. this.alignment,
  13. this.loadText, //提示加载文字
  14. this.loadReadyText, // 准备加载文字
  15. this.loadingText, // 正在加载文字
  16. this.loadedText, // 加载完成文字
  17. this.loadFailedText, // 加载失败文字
  18. this.noMoreText,
  19. this.showInfo: true,
  20. this.infoText,
  21. this.bgColor: Colors.transparent,
  22. this.textColor: Colors.black,
  23. this.infoColor: Colors.teal,
  24. })

构造器API

控制器

  1. import 'package:flutter_easyrefresh/easy_refresh.dart';
  2. EasyRefreshController _controller;
  3. initState(){
  4. _controller = EasyRefreshController();
  5. }
  6. _controller.callRefresh(); //触发刷新
  7. callLoad(); // 触发加载
  8. finishRefresh(); // 完成刷新
  9. finishLoad(); // 完成加载
  10. resetRefreshState(); // 恢复刷新状态(用于没有更多后)
  11. resetLoadState(); // 恢复加载状态(用于没有更多后)
  12. _controller._easyRefreshState; // 状态

默认构造器

  1. /// 默认构造器
  2. /// 将child转换为CustomScrollView可用的slivers
  3. EasyRefresh({
  4. Key key,
  5. this.controller, // 控制器
  6. this.scrollController,
  7. this.onRefresh, //刷新回调(null为不开启刷新)
  8. this.onLoad, // 加载回调(null为不开启加载)
  9. this.enableControlFinishRefresh = false, // 是否开启控制结束刷新
  10. this.enableControlFinishLoad = false, // 是否开启控制结束加载
  11. this.taskIndependence = false, // 任务独立(刷新和加载状态独立)
  12. this.header,
  13. this.headerIndex,
  14. this.footer,
  15. this.firstRefresh, // 首次刷新
  16. this.firstRefreshWidget, // 首次刷新组件,不设置时使用header
  17. this.emptyWidget, // 空视图,当不为null时,只会显示空视图,保留[headerIndex]以上的内容
  18. this.topBouncing = true, // 顶部回弹(Header的overScroll属性优先,且onRefresh和header都为null时生效)
  19. this.bottomBouncing = true, // 底部回弹(Footer的overScroll属性优先,且onLoad和footer都为null时生效)
  20. this.behavior = const EmptyOverScrollScrollBehavior(), // 滚动行为
  21. @required this.child,
  22. })

custom 构造器

  1. /// 直接使用CustomScrollView可用的slivers
  2. EasyRefresh.custom({
  3. ...
  4. this.listKey,
  5. this.scrollDirection = Axis.vertical, // 列表方向
  6. this.reverse = false, // 反向
  7. this.scrollController,
  8. this.primary,
  9. this.shrinkWrap = false,
  10. this.center,
  11. this.anchor = 0.0,
  12. this.cacheExtent,
  13. this.semanticChildCount,
  14. this.dragStartBehavior = DragStartBehavior.start,
  15. @required this.slivers,
  16. })

EasyRefresh.builder

  1. EasyRefresh.builder({
  2. Key key,
  3. this.controller,
  4. this.onRefresh,
  5. this.onLoad,
  6. this.enableControlFinishRefresh = false,
  7. this.enableControlFinishLoad = false,
  8. this.taskIndependence = false,
  9. this.scrollController,
  10. this.header,
  11. this.footer,
  12. this.firstRefresh,
  13. this.topBouncing = true,
  14. this.bottomBouncing = true,
  15. this.behavior = const EmptyOverScrollScrollBehavior(),
  16. @required this.builder, // 子组件构造器(final EasyRefreshChildBuilder builder;)
  17. })

EasyRefreshChildBuilder 构造函数

  1. typedef EasyRefreshChildBuilder = Widget Function(
  2. BuildContext context, ScrollPhysics physics, Widget header, Widget footer);

ScrollNotificationInterceptor() 滚动通知拦截器

滚动通知拦截器(用于拦截其他UI组件的滑动事件)。

经试验,不用该组件包裹,好像也没啥问题。

  1. import 'package:app1/utils/Base.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_easyrefresh/easy_refresh.dart';
  4. import 'package:flutter_swiper/flutter_swiper.dart';
  5. class SwiperRefresh extends StatefulWidget {
  6. @override
  7. _SwiperRefreshState createState() => _SwiperRefreshState();
  8. }
  9. class _SwiperRefreshState extends State<SwiperRefresh> {
  10. int _count = 20; // 条目总数
  11. @override
  12. Widget build(BuildContext context) {
  13. return Scaffold(
  14. body: EasyRefresh.builder(
  15. builder: (context, physics, header, footer) {
  16. return CustomScrollView(
  17. slivers: [
  18. SliverList(
  19. delegate: SliverChildListDelegate([
  20. Container(
  21. height: 210,
  22. // 滚动通知拦截器(用于拦截其他UI组件的滑动事件)
  23. child: ScrollNotificationInterceptor(
  24. child: Swiper(
  25. itemCount: 5,
  26. viewportFraction: 0.8,
  27. scale: 0.9,
  28. itemBuilder: (context, index) {
  29. return Container(
  30. height: double.infinity,
  31. color: Color(Base.getRandomColor()),
  32. child: Center(child: Text('swiper ${index + 1}', textScaleFactor: 2)),
  33. );
  34. },
  35. ),
  36. ),
  37. ),
  38. ]),
  39. ),
  40. ],
  41. );
  42. },
  43. ),
  44. );
  45. }
  46. }

例子

控制器控制-基本例子

ezgif-4-7327c95a2094.gif

  1. import 'package:app1/coms/base/empty_null/empty_null.dart';
  2. import 'package:app1/coms/loading/ELoading.dart';
  3. import 'package:app1/utils/Base.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_easyrefresh/easy_refresh.dart';
  6. class BaseRefresh extends StatefulWidget {
  7. @override
  8. _BaseRefreshState createState() => _BaseRefreshState();
  9. }
  10. class _BaseRefreshState extends State<BaseRefresh> {
  11. EasyRefreshController _controller;
  12. ScrollController _scrollController;
  13. var _count = 0; // 条目总数
  14. bool _enableControlFinish = false; // 控制结束
  15. @override
  16. void initState() {
  17. super.initState();
  18. _controller = EasyRefreshController();
  19. _scrollController = ScrollController();
  20. }
  21. getList({
  22. isRefresh = false,
  23. }) async {
  24. // ELoading.show();
  25. print('getList $isRefresh');
  26. await Future.delayed(Duration(seconds: 2));
  27. var temp = _count;
  28. if (isRefresh == true) {
  29. temp = 10;
  30. } else {
  31. temp += 10;
  32. }
  33. setState(() {
  34. _count = temp;
  35. });
  36. // ELoading.destroy();
  37. }
  38. @override
  39. Widget build(BuildContext context) {
  40. return Scrollbar(
  41. child: Container(
  42. width: double.infinity,
  43. height: double.infinity,
  44. child: EasyRefresh.custom(
  45. enableControlFinishRefresh: true, //是否开启控制结束刷新
  46. enableControlFinishLoad: true, //是否开启控制结束加载
  47. controller: _controller, // 控制器
  48. scrollController: _scrollController,
  49. header: ClassicalHeader(
  50. enableInfiniteRefresh: false,
  51. refreshText: '下拉刷新',
  52. refreshReadyText: '释放刷新',
  53. refreshingText: '刷新中...',
  54. refreshedText: '刷新完成',
  55. float: false, //是否浮动在列表之上
  56. ),
  57. footer: ClassicalFooter(
  58. enableInfiniteLoad: true, //是否开启无限加载
  59. loadText: '上拉加载',
  60. loadReadyText: '释放加载',
  61. loadingText: '加载中...',
  62. loadedText: '加载完成',
  63. noMoreText: '没有更多了',
  64. ),
  65. firstRefresh: true, // 是否需要首次刷新
  66. firstRefreshWidget: Center(child: Text('页面加载中...')), // 首次刷新加载组件
  67. emptyWidget: _count > 0 ? null : Center(child: Text('数据暂时为空')), //空视图
  68. onRefresh: () async {
  69. await getList(isRefresh: true);
  70. if (mounted) {
  71. if (!_enableControlFinish) {
  72. _controller.resetLoadState(); //恢复加载状态
  73. _controller.finishRefresh(); //完成刷新
  74. }
  75. }
  76. },
  77. onLoad: () async {
  78. await getList();
  79. if (mounted) {
  80. if (!_enableControlFinish) {
  81. _controller.finishLoad(noMore: _count >= 40);
  82. }
  83. }
  84. },
  85. slivers: [
  86. SliverList(
  87. delegate: SliverChildBuilderDelegate(
  88. (context, index) {
  89. return Container(
  90. color: Color(Base.getRandomColor()),
  91. height: 100,
  92. child: Text('我是文本 ${index + 1}', textScaleFactor: 3),
  93. );
  94. },
  95. childCount: _count,
  96. ),
  97. ),
  98. ],
  99. ),
  100. ),
  101. );
  102. }
  103. }

swiper 示例,解决滑动冲突

iuo.gif

  1. import 'package:app1/utils/Base.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_easyrefresh/easy_refresh.dart';
  4. import 'package:flutter_swiper/flutter_swiper.dart';
  5. class SwiperRefresh extends StatefulWidget {
  6. @override
  7. _SwiperRefreshState createState() => _SwiperRefreshState();
  8. }
  9. class _SwiperRefreshState extends State<SwiperRefresh> {
  10. int _count = 10; // 条目总数
  11. @override
  12. Widget build(BuildContext context) {
  13. return Scaffold(
  14. body: EasyRefresh.builder(
  15. onRefresh: () async {
  16. await Future.delayed(Duration(seconds: 2), () {
  17. if (mounted) {
  18. setState(() {
  19. _count = 10;
  20. });
  21. }
  22. });
  23. },
  24. onLoad: () async {
  25. await Future.delayed(Duration(seconds: 2), () {
  26. if (mounted) {
  27. setState(() {
  28. _count += 10;
  29. });
  30. }
  31. });
  32. },
  33. builder: (context, physics, header, footer) {
  34. return CustomScrollView(
  35. physics: physics,
  36. slivers: [
  37. SliverAppBar(
  38. pinned: true, //是否缩小到一定程度,不再缩小
  39. expandedHeight: 100.0,
  40. backgroundColor: Colors.red,
  41. flexibleSpace: FlexibleSpaceBar(
  42. title: Text('SwiperRefresh'),
  43. centerTitle: false,
  44. ),
  45. ),
  46. header,
  47. footer,
  48. SliverList(
  49. delegate: SliverChildListDelegate([
  50. Container(
  51. height: 210,
  52. // 滚动通知拦截器(用于拦截其他UI组件的滑动事件)
  53. child: ScrollNotificationInterceptor(
  54. child: Swiper(
  55. itemCount: 5,
  56. viewportFraction: 0.8,
  57. scale: 0.9,
  58. itemBuilder: (context, index) {
  59. return Container(
  60. height: double.infinity,
  61. color: Color(Base.getRandomColor()),
  62. child: Center(child: Text('swiper ${index + 1}', textScaleFactor: 2)),
  63. );
  64. },
  65. ),
  66. ),
  67. ),
  68. ]),
  69. ),
  70. SliverList(
  71. delegate: SliverChildBuilderDelegate(
  72. (context, index) {
  73. return Container(
  74. color: Color(Base.getRandomColor()),
  75. height: 100,
  76. child: Text('我是文本 ${index + 1}', textScaleFactor: 3),
  77. );
  78. },
  79. childCount: _count,
  80. ),
  81. ),
  82. ],
  83. );
  84. },
  85. ),
  86. );
  87. }
  88. }

首次刷新例子

iuortye.gif

  1. import 'package:app1/utils/Base.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_easyrefresh/easy_refresh.dart';
  4. class FirstRefresh extends StatefulWidget {
  5. @override
  6. _FirstRefreshState createState() => _FirstRefreshState();
  7. }
  8. class _FirstRefreshState extends State<FirstRefresh> {
  9. var _count = 0; // 条目总数
  10. @override
  11. Widget build(BuildContext context) {
  12. return Scrollbar(
  13. child: Container(
  14. width: double.infinity,
  15. height: double.infinity,
  16. child: EasyRefresh.custom(
  17. firstRefresh: true, // 是否需要首次刷新
  18. firstRefreshWidget: Center(child: Text('页面加载中...')), // 首次刷新加载组件
  19. onRefresh: () async {
  20. await Future.delayed(Duration(seconds: 2), () {
  21. if (mounted) {
  22. setState(() {
  23. _count = 10;
  24. });
  25. }
  26. });
  27. },
  28. onLoad: () async {
  29. await Future.delayed(Duration(seconds: 2), () {
  30. if (mounted) {
  31. setState(() {
  32. _count += 10;
  33. });
  34. }
  35. });
  36. },
  37. slivers: [
  38. SliverList(
  39. delegate: SliverChildBuilderDelegate(
  40. (context, index) {
  41. return Container(
  42. color: Color(Base.getRandomColor()),
  43. height: 100,
  44. child: Text('我是文本 ${index + 1}', textScaleFactor: 3),
  45. );
  46. },
  47. childCount: _count,
  48. ),
  49. ),
  50. ],
  51. ),
  52. ),
  53. );
  54. }
  55. }

空视图例子

image.png

  1. import 'package:app1/utils/Base.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_easyrefresh/easy_refresh.dart';
  4. class EmptyRefresh extends StatefulWidget {
  5. @override
  6. _EmptyRefreshState createState() => _EmptyRefreshState();
  7. }
  8. class _EmptyRefreshState extends State<EmptyRefresh> {
  9. var _count = 0; // 条目总数
  10. @override
  11. Widget build(BuildContext context) {
  12. return Scrollbar(
  13. child: Container(
  14. width: double.infinity,
  15. height: double.infinity,
  16. child: EasyRefresh.custom(
  17. emptyWidget: _count == 0 ? Center(child: Text('暂无数据')) : null, // 无数据时展示
  18. onRefresh: () async {
  19. await Future.delayed(Duration(seconds: 2), () {
  20. if (mounted) {
  21. setState(() {
  22. _count = 10;
  23. });
  24. }
  25. });
  26. },
  27. onLoad: () async {
  28. await Future.delayed(Duration(seconds: 2), () {
  29. if (mounted) {
  30. setState(() {
  31. _count += 10;
  32. });
  33. }
  34. });
  35. },
  36. slivers: [
  37. SliverList(
  38. delegate: SliverChildBuilderDelegate(
  39. (context, index) {
  40. return Container(
  41. color: Color(Base.getRandomColor()),
  42. height: 100,
  43. child: Text('我是文本 ${index + 1}', textScaleFactor: 3),
  44. );
  45. },
  46. childCount: _count,
  47. ),
  48. ),
  49. ],
  50. ),
  51. ),
  52. );
  53. }
  54. }

header连接器-例子

fdt.gif

  1. LinkHeader(
  2. this.linkNotifier, {
  3. extent = 60.0,
  4. triggerDistance = 70.0,
  5. completeDuration,
  6. enableHapticFeedback = false,
  7. })
  1. /// 链接通知器
  2. class LinkHeaderNotifier extends ChangeNotifier {
  3. BuildContext context;
  4. RefreshMode refreshState = RefreshMode.inactive; // 状态
  5. //inactive 未开始;
  6. //drag 拖拽中;
  7. //armed 拖拽到足够刷新;refresh 刷新中;
  8. //refreshed 刷新完成; done 刷新完成且动画结束
  9. double pulledExtent = 0.0; //下拉进度
  10. double refreshTriggerPullDistance;
  11. double refreshIndicatorExtent;
  12. AxisDirection axisDirection;
  13. bool float;
  14. Duration completeDuration;
  15. bool enableInfiniteRefresh;
  16. bool success = true;
  17. bool noMore = false;
  1. import 'package:app1/utils/Base.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_easyrefresh/easy_refresh.dart';
  4. class LinkHeaderDemo extends StatefulWidget {
  5. @override
  6. _LinkHeaderDemoState createState() => _LinkHeaderDemoState();
  7. }
  8. class _LinkHeaderDemoState extends State<LinkHeaderDemo> {
  9. int _count = 10; //总数
  10. LinkHeaderNotifier _headerNotifier; //连接通知器
  11. @override
  12. void initState() {
  13. super.initState();
  14. _headerNotifier = LinkHeaderNotifier();
  15. }
  16. @override
  17. void dispose() {
  18. super.dispose();
  19. _headerNotifier.dispose();
  20. }
  21. @override
  22. Widget build(BuildContext context) {
  23. return EasyRefresh.custom(
  24. header: LinkHeader(
  25. _headerNotifier,
  26. extent: 70.0,
  27. triggerDistance: 70.0,
  28. completeDuration: Duration(milliseconds: 500),
  29. ),
  30. slivers: [
  31. SliverAppBar(
  32. expandedHeight: 100.0,
  33. pinned: true,
  34. flexibleSpace: FlexibleSpaceBar(
  35. centerTitle: false,
  36. title: Text('Header 连接器'),
  37. ),
  38. actions: <Widget>[
  39. CircleHeader(_headerNotifier),
  40. ],
  41. ),
  42. SliverList(
  43. delegate: SliverChildBuilderDelegate(
  44. (context, index) {
  45. return Container(
  46. color: Color(Base.getRandomColor()),
  47. height: 100,
  48. child: Text('我是文本 ${index + 1}', textScaleFactor: 3),
  49. );
  50. },
  51. childCount: _count,
  52. ),
  53. ),
  54. ],
  55. onRefresh: () async {
  56. await Future.delayed(Duration(seconds: 2), () {
  57. if (mounted) {
  58. setState(() {
  59. _count = 10;
  60. });
  61. }
  62. });
  63. },
  64. onLoad: () async {
  65. await Future.delayed(Duration(seconds: 2), () {
  66. if (mounted) {
  67. setState(() {
  68. _count += 10;
  69. });
  70. }
  71. });
  72. },
  73. );
  74. }
  75. }
  1. // 圆形Header
  2. class CircleHeader extends StatefulWidget {
  3. final LinkHeaderNotifier linkNotifier;
  4. const CircleHeader(this.linkNotifier, {Key key}) : super(key: key);
  5. @override
  6. CircleHeaderState createState() => CircleHeaderState();
  7. }
  8. class CircleHeaderState extends State<CircleHeader> {
  9. // 指示器值
  10. double _indicatorValue = 0.0;
  11. RefreshMode get _refreshState => widget.linkNotifier.refreshState;
  12. double get _pulledExtent => widget.linkNotifier.pulledExtent;
  13. @override
  14. void initState() {
  15. super.initState();
  16. //下拉进度监听
  17. widget.linkNotifier.addListener(onLinkNotify);
  18. }
  19. //下拉进度监听-回调
  20. void onLinkNotify() {
  21. setState(() {
  22. if (_refreshState == RefreshMode.armed || _refreshState == RefreshMode.refresh) {
  23. _indicatorValue = null;
  24. } else if (_refreshState == RefreshMode.refreshed || _refreshState == RefreshMode.done) {
  25. _indicatorValue = 1.0;
  26. } else {
  27. if (_refreshState == RefreshMode.inactive) {
  28. _indicatorValue = 0.0;
  29. } else {
  30. double indicatorValue = _pulledExtent / 70.0 * 0.8;
  31. _indicatorValue = indicatorValue < 0.8 ? indicatorValue : 0.8;
  32. }
  33. }
  34. });
  35. }
  36. @override
  37. Widget build(BuildContext context) {
  38. return Center(
  39. child: Container(
  40. alignment: Alignment.center,
  41. margin: EdgeInsets.only(
  42. right: 20.0,
  43. ),
  44. width: 24.0,
  45. height: 24.0,
  46. child: CircularProgressIndicator(
  47. value: _indicatorValue,
  48. valueColor: AlwaysStoppedAnimation(Colors.black),
  49. strokeWidth: 2.4,
  50. ),
  51. ),
  52. );
  53. }
  54. }

extended_nested_scroll_view tab列表示例

https://www.yuque.com/zhuchaoyang/tnyvrp/vz7sxb

样式例子

Materail 质感设计,android样式

fdtdt.gif

  1. import 'package:app1/utils/Base.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter_easyrefresh/easy_refresh.dart';
  4. class StyleMaterial extends StatefulWidget {
  5. @override
  6. _StyleMaterialState createState() => _StyleMaterialState();
  7. }
  8. class _StyleMaterialState extends State<StyleMaterial> {
  9. var _count = 10; // 条目总数
  10. @override
  11. Widget build(BuildContext context) {
  12. return Scrollbar(
  13. child: EasyRefresh.custom(
  14. header: MaterialHeader(),
  15. footer: MaterialFooter(),
  16. onRefresh: () async {
  17. await Future.delayed(Duration(seconds: 2), () {
  18. if (mounted) {
  19. setState(() {
  20. _count = 10;
  21. });
  22. }
  23. });
  24. },
  25. onLoad: () async {
  26. await Future.delayed(Duration(seconds: 2), () {
  27. if (mounted) {
  28. setState(() {
  29. _count += 10;
  30. });
  31. }
  32. });
  33. },
  34. slivers: [
  35. SliverList(
  36. delegate: SliverChildBuilderDelegate(
  37. (context, index) {
  38. return Container(
  39. color: Color(Base.getRandomColor()),
  40. height: 100,
  41. child: Text('我是文本 ${index + 1}', textScaleFactor: 3),
  42. );
  43. },
  44. childCount: _count,
  45. ),
  46. ),
  47. ],
  48. ),
  49. );
  50. }
  51. }

球脉冲效果

文件: loading.zip
fdtdttydd.gif

  1. EasyRefresh.custom(
  2. header: MyLoading.pullDownLoading(),
  3. footer: MyLoading.pullUpLoading(),
  4. )

弹出圆圈

fdtdtty.gif

  1. EasyRefresh.custom(
  2. header: BezierCircleHeader(),
  3. footer: BezierBounceFooter(),
  4. )

弹出HourGlass

fdtdttydd.gif

  1. EasyRefresh.custom(
  2. header: BezierHourGlassHeader(
  3. color: Theme.of(context).scaffoldBackgroundColor,
  4. ),
  5. footer: BezierBounceFooter(
  6. color: Theme.of(context).scaffoldBackgroundColor,
  7. ),
  8. )

冲上云霄

fdtdttydd.gif

  1. EasyRefresh.custom(
  2. header: TaurusHeader(),
  3. footer: TaurusFooter(),
  4. )

金色校园

fdtdttydd.gif

  1. EasyRefresh.custom(
  2. header: PhoenixHeader(),
  3. footer: PhoenixFooter(),
  4. )

气球快递

fdtdttydd.gif

  1. EasyRefresh.custom(
  2. header: DeliveryHeader(
  3. backgroundColor: Colors.grey[100],
  4. ),
  5. )

星空

fdtdttydd.gif

  1. EasyRefresh.custom(
  2. header: SpaceHeader(),
  3. )

小黄人

fdtdttyddasd.gif

  1. EasyRefresh.custom(
  2. BobMinionHeader(animation: 'Jump'), //Stand Dance Jump Wave
  3. )