diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f02f1c8..ffb2e97a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -116,3 +116,8 @@ Notice: This version of the code changes much, Api too * implements auto hide FooterView when less than one page,no need to set enablePullUp to false * improve safety after disposed +## 1.3.3 +* Fixed the request Refresh problem: Sometimes it takes two times to be effective +* Add child key support +* Fix Bug:Pull-down triggers need to be pulled down more distances to trigger +* Add resetNoData to resume footer state to idle \ No newline at end of file diff --git a/README.md b/README.md index f061adaf..0b7c2cc6 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ If you are Chinese,click here([中文文档](https://github.com/peng8350/flutter ``` dependencies: - pull_to_refresh: ^1.3.2 + pull_to_refresh: ^1.3.3 ``` @@ -46,6 +46,8 @@ initState(){ super.initState(); _refreshController = RefreshController(); + // if you need refreshing when init + // _refreshController.requestRefresh(); } void _onRefresh(){ @@ -87,7 +89,8 @@ void dispose(){ ## Custom -1.In the first way, assuming that the indicator function you want to implement is not too complex, you can use CustomHeader or CustomFooter +1.In the first way, assuming that the indicator function you want to implement is not too complex, you can use CustomHeader or CustomFooter. +using onOffsetChange callback in SmartRefresher to implements some simple animation. ``` Widget buildHeader(BuildContext context,RefreshStatus mode){ diff --git a/README_CN.md b/README_CN.md index e5d7d48b..966a5e4c 100644 --- a/README_CN.md +++ b/README_CN.md @@ -28,7 +28,7 @@ ``` dependencies: - pull_to_refresh: ^1.3.2 + pull_to_refresh: ^1.3.3 ``` @@ -42,6 +42,8 @@ initState(){ super.initState(); _refreshController = RefreshController(); + // 如果你需要开始就请求一次刷新 + // _refreshController.requestRefresh(); } void _onRefresh(){ @@ -80,7 +82,7 @@ void dispose(){ ``` ## 自定义指示器 -1.第一种方式,假设你要实现的指示器功能不是太过于复杂,可以使用CustomHeader或者CustomFooter +1.第一种方式,假设你要实现的指示器功能不是太过于复杂,可以使用CustomHeader或者CustomFooter,利用SmartRefresher里的onOffsetChange回调可完成一些简单的动画 ``` Widget buildHeader(BuildContext context,RefreshStatus mode){ diff --git a/example/lib/ui/test/Example3.dart b/example/lib/ui/test/Example3.dart index 651842a0..8c66768b 100644 --- a/example/lib/ui/test/Example3.dart +++ b/example/lib/ui/test/Example3.dart @@ -24,14 +24,14 @@ class Example3State extends State with TickerProviderStateMixin { //test #68 - bool _enablePullUp=false,_enablePullDown=false; + bool _enablePullUp=true,_enablePullDown=true; void _getDatas() { data.add(Row(children: [ FlatButton(onPressed: (){ - _refreshController.requestRefresh(); + _refreshController.requestRefresh(needDownAnimate: false); }, child: Text("请求刷新")), FlatButton(onPressed: (){ _refreshController.requestLoading(); @@ -114,7 +114,6 @@ class Example3State extends State with TickerProviderStateMixin { // // }); // }); -// // Future.delayed(Duration(milliseconds: 3000),(){ // _enablePullDown = true; // _enablePullUp = false; @@ -132,8 +131,10 @@ class Example3State extends State with TickerProviderStateMixin { // }); // }); _getDatas(); - _scrollController = ScrollController(keepScrollOffset: true); _refreshController = RefreshController(); +// SchedulerBinding.instance.addPostFrameCallback((_){ +// _refreshController.requestRefresh(needDownAnimate: false); +// }); super.initState(); } @@ -157,8 +158,8 @@ class Example3State extends State with TickerProviderStateMixin { child: Stack( children: [ SmartRefresher( - enablePullUp: true, - enablePullDown: true, + enablePullUp: _enablePullDown, + enablePullDown: _enablePullUp, controller: _refreshController, header: WaterDropHeader(waterDropColor: Colors.greenAccent), footer: ClassicFooter( @@ -168,6 +169,7 @@ class Example3State extends State with TickerProviderStateMixin { }, ), onRefresh: () { + print("onRefresh"); Future.delayed(const Duration(milliseconds: 2009)).then((val) { _refreshController.refreshFailed(); }); diff --git a/lib/src/internals/indicator_wrap.dart b/lib/src/internals/indicator_wrap.dart index 14e0ea9d..4d020075 100644 --- a/lib/src/internals/indicator_wrap.dart +++ b/lib/src/internals/indicator_wrap.dart @@ -5,7 +5,6 @@ */ import 'dart:async'; -import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart'; import 'default_constants.dart'; import 'dart:math' as math; @@ -69,6 +68,7 @@ abstract class RefreshIndicatorState if (overscrollPast < 0.0) { return; } + if (refresher.widget.onOffsetChange != null) { refresher.widget.onOffsetChange(true, overscrollPast); } @@ -87,8 +87,8 @@ abstract class RefreshIndicatorState // handle the state change between canRefresh and idle canRefresh before refreshing void handleDragMove(double offset) { - if (floating) return; + if (_scrollController.position.activity.velocity == 0.0) { if (offset >= widget.triggerDistance) { mode = RefreshStatus.canRefresh; @@ -108,30 +108,21 @@ abstract class RefreshIndicatorState if (!mounted) { return; } + update(); - switch (mode) { - case RefreshStatus.refreshing: - floating = true; + if (mode == RefreshStatus.completed || mode == RefreshStatus.failed) { + endRefresh().then((_) { + floating = false; update(); - readyToRefresh().then((_) { - if (refresher.widget.onRefresh != null) refresher.widget.onRefresh(); - }); - break; - case RefreshStatus.completed: - endRefresh().then((_) { - floating = false; - update(); - }); - - break; - case RefreshStatus.failed: - endRefresh().then((_) { - floating = false; - update(); - }); - break; - default: - break; + // make gesture release + (_scrollController.position as ScrollActivityDelegate).goIdle(); + }); + } else if (mode == RefreshStatus.refreshing) { + floating = true; + update(); + readyToRefresh().then((_) { + if (refresher.widget.onRefresh != null) refresher.widget.onRefresh(); + }); } } @@ -175,6 +166,7 @@ abstract class RefreshIndicatorState // TODO: implement initState _scrollController = refresher.scrollController; + _headerMode = refresher.widget.controller.headerMode; // it is necessary,sometime the widget may be dispose ,it should be resume the state _headerMode.value = RefreshStatus.idle; diff --git a/lib/src/internals/slivers.dart b/lib/src/internals/slivers.dart index ac7d2037..edb126d9 100644 --- a/lib/src/internals/slivers.dart +++ b/lib/src/internals/slivers.dart @@ -115,7 +115,7 @@ class _RenderSliverRefresh extends RenderSliver layoutExtentOffsetCompensation = layoutExtent; return; } - final bool active = constraints.overlap <= 0.0 || layoutExtent >= 0.0; + final bool active = constraints.overlap < 0.0 || layoutExtent > 0.0; final double overscrolledExtent = constraints.overlap.abs(); if (refreshStyle == RefreshStyle.Behind) { child.layout( diff --git a/lib/src/smart_refresher.dart b/lib/src/smart_refresher.dart index 7842299f..cd6c2833 100644 --- a/lib/src/smart_refresher.dart +++ b/lib/src/smart_refresher.dart @@ -167,19 +167,36 @@ class RefreshController { ScrollController scrollController; RefreshIndicator _header; + RefreshStatus get headerStatus => headerMode?.value; + + LoadStatus get footerStatus => footerMode?.value; + + bool get isRefresh => headerMode?.value == RefreshStatus.refreshing; + + bool get isLoading => footerMode?.value == LoadStatus.loading; + void requestRefresh( {bool needDownAnimate: true, - Duration duration: const Duration(milliseconds: 400), + Duration duration: const Duration(milliseconds: 300), Curve curve: Curves.linear}) { assert(scrollController != null, 'Try not to call requestRefresh() before build,please call after the ui was rendered'); - if (headerStatus == RefreshStatus.idle) - scrollController.animateTo(-_header.triggerDistance, - duration: duration, curve: curve); + if(headerMode?.value !=RefreshStatus.idle)return; + if(needDownAnimate){ + scrollController.animateTo(-_header.triggerDistance, duration: duration, curve: curve); + } + else { + headerMode?.value = RefreshStatus.refreshing; + // only afte the header has Layout,else it will generate a bouncing effect + SchedulerBinding.instance.addPostFrameCallback((_){ + scrollController.jumpTo(0.0); + }); + + } } void requestLoading( - {Duration duration: const Duration(milliseconds: 200), + {Duration duration: const Duration(milliseconds: 300), Curve curve: Curves.linear}) { assert(scrollController != null, 'Try not to call requestLoading() before build,please call after the ui was rendered'); @@ -210,6 +227,10 @@ class RefreshController { }); } + void resetNoData() { + footerMode?.value = LoadStatus.idle; + } + void dispose() { headerMode.dispose(); footerMode.dispose(); @@ -217,11 +238,5 @@ class RefreshController { footerMode = null; } - RefreshStatus get headerStatus => headerMode?.value; - - LoadStatus get footerStatus => footerMode?.value; - bool get isRefresh => headerMode?.value == RefreshStatus.refreshing; - - bool get isLoading => footerMode?.value == LoadStatus.loading; } diff --git a/pubspec.yaml b/pubspec.yaml index 3e33ec04..dbc9c4a9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: pull_to_refresh description: a widget provided to the flutter scroll component drop-down refresh and pull up load. -version: 1.3.2 +version: 1.3.3 author: Jpeng homepage: https://github.com/peng8350/flutter_pulltorefresh