From 485d8705c4732a5a7e83791e3a4da787a30c5d30 Mon Sep 17 00:00:00 2001 From: Jpeng Date: Wed, 12 Jun 2019 00:05:36 +0800 Subject: [PATCH] release 1.4.4 --- CHANGELOG.md | 8 +- README.md | 11 +- README_CN.md | 10 +- example/lib/ui/Item.dart | 2 +- example/lib/ui/MainActivity.dart | 86 ++++++++----- example/lib/ui/SecondActivity.dart | 1 + .../ui/indicator/base/IndicatorActivity.dart | 25 ++-- example/lib/ui/sample/Appbar_header.dart | 10 +- example/lib/ui/sample/BigData.dart | 23 ++-- example/lib/ui/sample/Dynamic+Navigator.dart | 91 ++++++-------- example/lib/ui/sample/InnerWrapList.dart | 12 +- example/lib/ui/sample/Nested.dart | 58 ++++----- example/lib/ui/sample/RequestRefresh.dart | 64 +++++----- example/lib/ui/sample/SamplePage.dart | 19 ++- example/lib/ui/screen/ScreenPage.dart | 12 +- example/lib/ui/screen/bilibili.dart | 59 ++++++--- example/lib/ui/screen/cupertinoScreen.dart | 117 +++++++++--------- example/lib/ui/screen/qqzone.dart | 46 ++++--- example/lib/ui/test/Example1.dart | 90 +++++++------- example/lib/ui/test/Example2.dart | 11 +- example/lib/ui/test/Example3.dart | 76 ++++++------ example/lib/ui/test/Example4.dart | 11 +- example/lib/ui/test/TestPage.dart | 70 ++++++----- lib/pull_to_refresh.dart | 2 +- lib/src/indicator/classic_indicator.dart | 2 +- lib/src/indicator/custom_indicator.dart | 5 +- lib/src/internals/indicator_wrap.dart | 43 +++++-- lib/src/internals/refresh_physics.dart | 77 ++++++------ lib/src/internals/slivers.dart | 11 +- lib/src/smart_refresher.dart | 66 +++++----- pubspec.yaml | 2 +- 31 files changed, 595 insertions(+), 525 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c985cdc9..5ef03305 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -172,4 +172,10 @@ Notice: This version of the code changes much, Api too * Fix triggerDistance error after 1.4.0-1.4.1 ## 1.4.3 -* change "child" attr limit type from ScrollView to Widget \ No newline at end of file +* change "child" attr limit type from ScrollView to Widget + +## 1.4.4 +* Fix Bug:Multiples ScrollPositions shared one ScrollController,when calling controller.requestRefresh cause refresh together( such as keepAlive Widget ) +* When the user Dragging ScrollView(pull up), disable make it change to loading state +* Add one new LoadStatus:failed(provide click to retry loading) +* Fix some defaultIcon:noMoreIcon default Invisible \ No newline at end of file diff --git a/README.md b/README.md index f598964e..03857127 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,11 @@ If you are Chinese,click here([中文文档](https://github.com/peng8350/flutter ## How to use? +Because 1.3.0 has made great changes to the internal, version 1.3.0-1.3.9 is not recommended to use,there has a lot of Bug , 1.4.0 began to stabilize. ``` dependencies: - pull_to_refresh: ^1.4.3 + pull_to_refresh: ^1.4.4 ``` @@ -128,10 +129,10 @@ the [example](https://github.com/peng8350/flutter_pulltorefresh/blob/master/exam This problem is not my encapsulation error after testing. When the controller in ListView is replaced, this problem will occur, probably because of the processing operation in Scaffold.,please issue flutter。 -*

How to use it with NestedScrollView?

-1.3.0 provides a new attribute isNestWrapped for compatibility. Note that when this attribute is opened, scollController depends on NestScrollView, -internally via PrimaryScrollController. of (context) To get scrollController, scrollController is placed in NestedScrollView。 -(The isNestWrapped attribute is unnecessary after 1.3.8) +*

Is Supporting NestedScrollView?

+It's not recommended to use NestedScrollView. Now I have found a problem that I need to modify the internal source code of + NestedScrollView to solve. So it's better to use CustomScrollView to avoid using it, because there may be many unknown + problems that I haven't found yet. *

Why is there a empty space in the top or tail indicator after using CuperNavigationBar (not just in this case)?

the reason may be SafeArea,the solution: wrap SmartRefresher in SafeArea diff --git a/README_CN.md b/README_CN.md index 9fa27be9..2c4b778e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -32,11 +32,11 @@ ## 我该怎么用? - +因1.3.0对内部进行了很大的变动,1.3.0~1.3.9版本不建议使用,Bug较多,1.4.0开始稳定 ``` dependencies: - pull_to_refresh: ^1.4.3 + pull_to_refresh: ^1.4.4 ``` @@ -126,9 +126,9 @@ header和footer的重复性的工作,在RefreshConfiguration子树下的SmartRef *

IOS状态栏双击为什么ListView不自动滚动到顶部?

这个问题经测试不是我封装的失误,当ListView里的controller被替换后,这个问题就会出现,原因大概是Scaffold里的处理操作,请issue flutter。 -*

如何兼容NestedScrollView?

-1.3.0提供了一个新属性isNestWrapped来兼容这东西,注意,这个属性打开后,scollController取决于NestScrollView,内部通过PrimaryScrollController.of(context) -来获取scrollController,所以scrollController要放在NestedScrollView里。(1.3.8后isNestWrapped就没必要使用了) +*

NestedScrollView兼容性?

+不建议使用NestedScrollView,目前我已经发现了一个问题,要修改NestedScrollView内部源代码才能解决,所以最好用CustomScrollView,避免使用它, +因为可能还有很多未知的问题我还没有发现。 *

为什么使用CuperNavigationBar后(不只这一个情况),顶部或者尾部指示器有空白的地方?

很大可能是因为SafeArea,。解决方法一般是在SmartRefresher外围套用SafeArea diff --git a/example/lib/ui/Item.dart b/example/lib/ui/Item.dart index d741178a..25985c5f 100644 --- a/example/lib/ui/Item.dart +++ b/example/lib/ui/Item.dart @@ -6,10 +6,10 @@ import 'package:flutter/material.dart'; class Item extends StatefulWidget { - final String title; Item({this.title}); + @override _ItemState createState() => _ItemState(); } diff --git a/example/lib/ui/MainActivity.dart b/example/lib/ui/MainActivity.dart index 0df2cd33..10fe41dc 100644 --- a/example/lib/ui/MainActivity.dart +++ b/example/lib/ui/MainActivity.dart @@ -66,8 +66,32 @@ class _MainActivityState extends State // TODO: implement build return ResideMenu.scaffold( controller: _menuController, - enable3dRotate: true, + enable3dRotate: true, child: Scaffold( + appBar: AppBar( + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text(_tabIndex == 0 + ? "指示器界面" + : _tabIndex == 1 ? "测试界面" : _tabIndex == 2 ? "样例界面" : "App界面"), + leading: GestureDetector(child: Icon(Icons.menu),onTap: (){ + _menuController.openMenu(true); + },), + backgroundColor: Colors.greenAccent, + bottom: _tabIndex==2?TabBar(isScrollable: true, + tabs: [ + Tab(child: Text("超大数据量性能测试")), + Tab( + child: Text("NestedScrollView兼容"), + ), + Tab(child: Text("SliverAppbar+Sliverheader")), + Tab(child: Text("嵌套滚动视图")), + Tab(child: Text("动态变化指示器+Navigator")), + Tab(child: Text("主动刷新")), + ], + controller: _tabController, + ):null, + ), body: RefreshConfiguration( child: PageView( @@ -78,9 +102,9 @@ class _MainActivityState extends State clickLoadingWhenIdle: true, headerTriggerDistance: 80.0, autoLoad: true, - hideFooterWhenNotFull: true, + hideFooterWhenNotFull: false, headerBuilder: () => WaterDropHeader(waterDropColor: Colors.green,), - footerBuilder: () => ClassicFooter(), + footerBuilder: () => ClassicFooter(decoration: BoxDecoration(color: Colors.pink),), ), ), decoration: BoxDecoration(color: Colors.purple), @@ -95,39 +119,39 @@ class _MainActivityState extends State ), children: [ buildItem("各种指示器", Icon(Icons.apps, size: 18, color: Colors.grey), - () { - setState(() { - _tabIndex = 0; - }); - _pageController.jumpToPage(0); - _menuController.closeMenu(); - }), + () { + setState(() { + _tabIndex = 0; + }); + _pageController.jumpToPage(0); + _menuController.closeMenu(); + }), buildItem("测试", Icon(Icons.airplanemode_active, size: 18, color: Colors.grey), - () { - setState(() { - _tabIndex = 1; - }); - _menuController.closeMenu(); - _pageController.jumpToPage(1); - }), + () { + setState(() { + _tabIndex = 1; + }); + _menuController.closeMenu(); + _pageController.jumpToPage(1); + }), buildItem("样例", Icon(Icons.scanner, size: 18, color: Colors.grey), - () { - setState(() { - _tabIndex = 2; - }); - _menuController.closeMenu(); - _pageController.jumpToPage(2); - }), + () { + setState(() { + _tabIndex = 2; + }); + _menuController.closeMenu(); + _pageController.jumpToPage(2); + }), buildItem( "App界面", Icon(Icons.format_underlined, size: 18, color: Colors.grey), - () { - setState(() { - _tabIndex = 3; - }); - _menuController.closeMenu(); - _pageController.jumpToPage(3); - }), + () { + setState(() { + _tabIndex = 3; + }); + _menuController.closeMenu(); + _pageController.jumpToPage(3); + }), ], ), ); diff --git a/example/lib/ui/SecondActivity.dart b/example/lib/ui/SecondActivity.dart index e5c03af0..25d7fde7 100644 --- a/example/lib/ui/SecondActivity.dart +++ b/example/lib/ui/SecondActivity.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; class SecondActivity extends StatefulWidget { SecondActivity({Key key, this.title}) : super(key: key); + // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect // how it looks. diff --git a/example/lib/ui/indicator/base/IndicatorActivity.dart b/example/lib/ui/indicator/base/IndicatorActivity.dart index a07b216b..65da8795 100644 --- a/example/lib/ui/indicator/base/IndicatorActivity.dart +++ b/example/lib/ui/indicator/base/IndicatorActivity.dart @@ -17,14 +17,13 @@ class IndicatorActivity extends StatefulWidget { final LoadIndicator footer; - final bool enableOverScroll; final bool reverse; IndicatorActivity( {this.title, this.header, - this.reverse:false, + this.reverse: false, this.footer, this.enableOverScroll: true}); @@ -41,12 +40,12 @@ class _IndicatorActivityState extends State { void _init() { for (int i = 0; i < 5; i++) { - items.add(Item(title: "Data$i",)); + items.add(Item( + title: "Data$i", + )); } } - - ScrollController _scrollController; @override @@ -54,7 +53,7 @@ class _IndicatorActivityState extends State { // TODO: implement initState _scrollController = new ScrollController(); _refreshController = RefreshController(); - Future.delayed(Duration(milliseconds: 3000)).then((_){ + Future.delayed(Duration(milliseconds: 3000)).then((_) { // _jumpTo(0.0); }); _init(); @@ -104,10 +103,7 @@ class _IndicatorActivityState extends State { print("onRefresh"); Future.delayed(Duration(milliseconds: 1000)).then((_) { items.add(Item(title: "Data")); - if(mounted) - setState(() { - - }); + if (mounted) setState(() {}); _refreshController.refreshCompleted(); }); } @@ -116,13 +112,12 @@ class _IndicatorActivityState extends State { print("onLoading"); Future.delayed(Duration(milliseconds: 1000)).then((_) { int index = items.length; - if(mounted) - setState(() {}); - items.add(Item(title: "Data$index",)); + if (mounted) setState(() {}); + items.add(Item( + title: "Data$index", + )); ; _refreshController.loadComplete(); - }); } } - diff --git a/example/lib/ui/sample/Appbar_header.dart b/example/lib/ui/sample/Appbar_header.dart index b2459961..4bc5390a 100644 --- a/example/lib/ui/sample/Appbar_header.dart +++ b/example/lib/ui/sample/Appbar_header.dart @@ -8,7 +8,6 @@ import 'package:flutter/material.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:flutter_sticky_header/flutter_sticky_header.dart'; - class AppBarHeader extends StatefulWidget { @override _AppBarHeaderState createState() => new _AppBarHeaderState(); @@ -39,7 +38,7 @@ class _AppBarHeaderState extends State { List buildList() { List items = []; - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 10; i++) { items.add(Text('样例数据')); } return items; @@ -60,9 +59,9 @@ class _AppBarHeaderState extends State { child: SmartRefresher( headerInsertIndex: 1, enablePullDown: true, + enablePullUp: true, child: CustomScrollView( slivers: [ - SliverAppBar( backgroundColor: Colors.greenAccent, expandedHeight: 200.0, @@ -78,11 +77,10 @@ class _AppBarHeaderState extends State { ], ), controller: _refreshController, - onRefresh: (){ + onRefresh: () { _refreshController.refreshCompleted(); }, - header: ClassicHeader( - ), + header: ClassicHeader(), ), ); } diff --git a/example/lib/ui/sample/BigData.dart b/example/lib/ui/sample/BigData.dart index a678d77b..d5622928 100644 --- a/example/lib/ui/sample/BigData.dart +++ b/example/lib/ui/sample/BigData.dart @@ -14,13 +14,14 @@ class DataSmall extends StatefulWidget { } class _DataSmallState extends State { - List items = []; RefreshController _refreshController; void _init() { for (int i = 0; i < 5000; i++) { - items.add(Item(title: "Data$i",)); + items.add(Item( + title: "Data$i", + )); } } @@ -28,21 +29,19 @@ class _DataSmallState extends State { void initState() { // TODO: implement initState _init(); - _refreshController = RefreshController(); + _refreshController = RefreshController(); super.initState(); } - _onLoading(){ + _onLoading() { _refreshController.loadComplete(); } - _onRefresh(){ - - items.add(Item(title: "Data",)); - if(mounted) - setState(() { - - }); + _onRefresh() { + items.add(Item( + title: "Data", + )); + if (mounted) setState(() {}); _refreshController.refreshCompleted(); } @@ -57,7 +56,7 @@ class _DataSmallState extends State { onRefresh: _onRefresh, onLoading: _onLoading, enablePullDown: true, - enablePullUp:true, + enablePullUp: true, controller: _refreshController); } diff --git a/example/lib/ui/sample/Dynamic+Navigator.dart b/example/lib/ui/sample/Dynamic+Navigator.dart index 0c1a7fe3..e33784b6 100644 --- a/example/lib/ui/sample/Dynamic+Navigator.dart +++ b/example/lib/ui/sample/Dynamic+Navigator.dart @@ -4,8 +4,6 @@ * Time: 2019-06-03 12:54 */ - - import 'package:flutter/material.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import '../Item.dart'; @@ -22,35 +20,30 @@ class Dynamic extends StatefulWidget { } class _DynamicState extends State { - List items = []; bool _enablePullDown = true; bool _enablePullUp = true; RefreshController _refreshController; void _init() { - items=[]; + items = []; items.add(Row( children: [ Text("打开下拉刷新"), Radio( value: true, - groupValue:_enablePullDown , + groupValue: _enablePullDown, onChanged: (i) { - _enablePullDown=i; - setState(() { - - }); + _enablePullDown = i; + setState(() {}); }, ), Radio( value: false, - groupValue:_enablePullDown , + groupValue: _enablePullDown, onChanged: (i) { - _enablePullDown=i; - setState(() { - - }); + _enablePullDown = i; + setState(() {}); }, ) ], @@ -60,22 +53,18 @@ class _DynamicState extends State { Text("打开上拉加载"), Radio( value: true, - groupValue:_enablePullUp , + groupValue: _enablePullUp, onChanged: (i) { - _enablePullUp=i; - setState(() { - - }); + _enablePullUp = i; + setState(() {}); }, ), Radio( value: false, - groupValue:_enablePullUp , + groupValue: _enablePullUp, onChanged: (i) { - _enablePullUp=i; - setState(() { - - }); + _enablePullUp = i; + setState(() {}); }, ) ], @@ -85,38 +74,39 @@ class _DynamicState extends State { children: [ MaterialButton( child: Text("延时打开/关闭下拉刷新"), - onPressed: (){ - Future.delayed(Duration(milliseconds: 2000)).whenComplete((){ + onPressed: () { + Future.delayed(Duration(milliseconds: 2000)).whenComplete(() { _enablePullDown = !_enablePullDown; - setState(() { - - }); + setState(() {}); }); }, ), MaterialButton( child: Text("延时打开/关闭上拉加载"), - onPressed: (){ - Future.delayed(Duration(milliseconds: 2000)).whenComplete((){ + onPressed: () { + Future.delayed(Duration(milliseconds: 2000)).whenComplete(() { _enablePullUp = !_enablePullUp; - setState(() { - - }); + setState(() {}); }); }, ), - ], )); - items.add( MaterialButton( + items.add(MaterialButton( child: Text("跳转第二个页面"), - onPressed: (){ - Navigator.of(context).push(MaterialPageRoute(builder: (c) => Scaffold(appBar:AppBar(),body: Container(),))); + onPressed: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (c) => Scaffold( + appBar: AppBar(), + body: Container(), + ))); }, )); for (int i = 0; i < 24; i++) { - items.add(Item(title: "Data$i",)); + items.add(Item( + title: "Data$i", + )); } } @@ -124,21 +114,22 @@ class _DynamicState extends State { void initState() { // TODO: implement initState - _refreshController = RefreshController(); + _refreshController = RefreshController(); super.initState(); } - _onLoading(){ - } + _onLoading() { + Future.delayed(Duration(milliseconds: 1000)).whenComplete((){ + _refreshController.loadComplete(); + }); + } - _onRefresh(){ - - items.add(Item(title: "Data",)); - if(mounted) - setState(() { - - }); + _onRefresh() { + items.add(Item( + title: "Data", + )); + if (mounted) setState(() {}); _refreshController.refreshCompleted(); } @@ -155,7 +146,7 @@ class _DynamicState extends State { onLoading: _onLoading, header: MaterialClassicHeader(), enablePullDown: _enablePullDown, - enablePullUp:_enablePullUp, + enablePullUp: _enablePullUp, controller: _refreshController); } diff --git a/example/lib/ui/sample/InnerWrapList.dart b/example/lib/ui/sample/InnerWrapList.dart index 9bc13bb4..63677e6c 100644 --- a/example/lib/ui/sample/InnerWrapList.dart +++ b/example/lib/ui/sample/InnerWrapList.dart @@ -47,8 +47,8 @@ class _InnerListState extends State { scrollDirection: Axis.horizontal, ), )); - for(int i =0;i<50;i++){ - items.add(Item(title:"数据")); + for (int i = 0; i < 50; i++) { + items.add(Item(title: "数据")); } } @@ -61,15 +61,17 @@ class _InnerListState extends State { } _onLoading() { - _refreshController.loadComplete(); + Future.delayed(Duration(milliseconds: 300)).whenComplete((){ + _refreshController.loadComplete(); + }); + } _onRefresh() { items.add(Item( title: "Data", )); - if(mounted) - setState(() {}); + if (mounted) setState(() {}); _refreshController.refreshCompleted(); } diff --git a/example/lib/ui/sample/Nested.dart b/example/lib/ui/sample/Nested.dart index 2d8d2382..64401647 100644 --- a/example/lib/ui/sample/Nested.dart +++ b/example/lib/ui/sample/Nested.dart @@ -8,7 +8,6 @@ import 'package:flutter/material.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import '../Item.dart'; - // test NestedScrollView compatibility class Nested extends StatefulWidget { @override @@ -21,7 +20,9 @@ class _NestedState extends State { void _init() { for (int i = 0; i < 14; i++) { - items.add(Item(title: "Data$i",)); + items.add(Item( + title: "Data$i", + )); } } @@ -29,25 +30,24 @@ class _NestedState extends State { void initState() { // TODO: implement initState _init(); - _refreshController = RefreshController(); + _refreshController = RefreshController(); super.initState(); } + @override Widget build(BuildContext context) { return NestedScrollView( headerSliverBuilder: (c, s) => [ - SliverAppBar( - backgroundColor: Colors.greenAccent, - expandedHeight: 200.0, - pinned: true, - flexibleSpace: FlexibleSpaceBar( - centerTitle: true, - background: Image.network( - "https://images.unsplash.com/photo-1541701494587-cb58502866ab?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=0c21b1ac3066ae4d354a3b2e0064c8be&auto=format&fit=crop&w=500&q=60", - fit: BoxFit.cover, - )), - ), - ], + SliverAppBar( + backgroundColor: Colors.greenAccent, + flexibleSpace: FlexibleSpaceBar( + centerTitle: true, + background: Image.network( + "https://images.unsplash.com/photo-1541701494587-cb58502866ab?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=0c21b1ac3066ae4d354a3b2e0064c8be&auto=format&fit=crop&w=500&q=60", + fit: BoxFit.cover, + )), + ), + ], body: SmartRefresher( controller: _refreshController, enablePullDown: true, @@ -57,23 +57,23 @@ class _NestedState extends State { ), enablePullUp: true, onRefresh: () { - Future.delayed(const Duration(milliseconds: 2009)) - .then((val) { - items.add(Item(title:"item")); - if(mounted) - setState(() { - _refreshController.refreshCompleted(); + Future.delayed(const Duration(milliseconds: 2009)).then((val) { + items.add(Item(title: "item")); + Future.delayed(Duration(milliseconds: 100)).then((_){ + if (mounted) + setState(() { + _refreshController.refreshCompleted(); + }); }); }); }, - onLoading: (){ - Future.delayed(const Duration(milliseconds: 2009)) - .then((val) { - if(mounted) - setState(() { - items.add(Item(title:"item")); - _refreshController.loadComplete(); - }); + onLoading: () { + Future.delayed(const Duration(milliseconds: 2009)).then((val) { + if (mounted) + setState(() { + items.add(Item(title: "item")); + _refreshController.loadComplete(); + }); }); }, child: ListView.builder( diff --git a/example/lib/ui/sample/RequestRefresh.dart b/example/lib/ui/sample/RequestRefresh.dart index 96073585..8aa351fc 100644 --- a/example/lib/ui/sample/RequestRefresh.dart +++ b/example/lib/ui/sample/RequestRefresh.dart @@ -17,44 +17,42 @@ class RequestRefresh extends StatefulWidget { } class _RequestRefreshState extends State { - List items = []; bool _enablePullDown = true; bool _enablePullUp = true; RefreshController _refreshController; RefreshIndicator _header = MaterialClassicHeader(); - void _init() { - items=[]; - items.add(Row(children: [MaterialButton( - child: Text("切换为Front"), - onPressed:(){ - _header = MaterialClassicHeader(); - setState(() { - }); - } - ),MaterialButton( - child: Text("切换为非Front"), - onPressed:(){ - _header = ClassicHeader(); - setState(() { - - }); - } - )],)); + void _init() { + items = []; + items.add(Row( + children: [ + MaterialButton( + child: Text("切换为Front"), + onPressed: () { + _header = MaterialClassicHeader(); + setState(() {}); + }), + MaterialButton( + child: Text("切换为非Front"), + onPressed: () { + _header = ClassicHeader(); + setState(() {}); + }) + ], + )); for (int i = 0; i < 24; i++) { items.add(GestureDetector( child: Container( child: Card( - child: Text(i%2!=0?"点我主动刷新!":"点我主动加载更多!"), + child: Text(i % 2 != 0 ? "点我主动刷新!" : "点我主动加载更多!"), ), height: 100.0, ), - onTap: (){ - if(i%2!=0){ + onTap: () { + if (i % 2 != 0) { _refreshController.requestRefresh(); - } - else{ + } else { _refreshController.requestLoading(); } }, @@ -65,20 +63,18 @@ class _RequestRefreshState extends State { @override void initState() { // TODO: implement initState - _refreshController = RefreshController(initialRefresh: true); + _refreshController = RefreshController(initialRefresh: true); super.initState(); } - _onLoading(){ + _onLoading() { + Future.delayed(Duration(milliseconds: 1000)).whenComplete((){ + _refreshController.loadComplete(); + }); } - - _onRefresh(){ - - if(mounted) - setState(() { - - }); + _onRefresh() { + if (mounted) setState(() {}); _refreshController.refreshCompleted(); } @@ -95,7 +91,7 @@ class _RequestRefreshState extends State { onLoading: _onLoading, header: _header, enablePullDown: _enablePullDown, - enablePullUp:_enablePullUp, + enablePullUp: _enablePullUp, controller: _refreshController); } diff --git a/example/lib/ui/sample/SamplePage.dart b/example/lib/ui/sample/SamplePage.dart index ab0a813e..72890e92 100644 --- a/example/lib/ui/sample/SamplePage.dart +++ b/example/lib/ui/sample/SamplePage.dart @@ -12,7 +12,6 @@ import 'RequestRefresh.dart'; import 'Dynamic+Navigator.dart'; class SamplePage extends StatefulWidget { - final TabController tabController; SamplePage({this.tabController}); @@ -24,21 +23,29 @@ class SamplePage extends StatefulWidget { } } -class _SamplePage extends State - { - +class _SamplePage extends State { List views; @override void initState() { // TODO: implement initState - views = [DataSmall(),Nested(),AppBarHeader(),InnerList(),Dynamic(),RequestRefresh()]; + views = [ + DataSmall(), + Nested(), + AppBarHeader(), + InnerList(), + Dynamic(), + RequestRefresh() + ]; super.initState(); } @override Widget build(BuildContext context) { // TODO: implement build - return TabBarView(children: views,controller: widget.tabController,); + return TabBarView( + children: views, + controller: widget.tabController, + ); } } diff --git a/example/lib/ui/screen/ScreenPage.dart b/example/lib/ui/screen/ScreenPage.dart index e14dfad6..7d028bcd 100644 --- a/example/lib/ui/screen/ScreenPage.dart +++ b/example/lib/ui/screen/ScreenPage.dart @@ -14,19 +14,22 @@ class ScreenPage extends StatelessWidget { _Item( title: "哔哩哔哩首页", onClick: (BuildContext context) { - Navigator.of(context).push( MaterialPageRoute(builder: (BuildContext context) => BiliBiliScreen())); + Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) => BiliBiliScreen())); }, ), _Item( title: "QQ空间", onClick: (BuildContext context) { - Navigator.of(context).push( MaterialPageRoute(builder: (BuildContext context) => qqZone())); + Navigator.of(context).push( + MaterialPageRoute(builder: (BuildContext context) => qqZone())); }, ), _Item( title: "iOS界面(主要测试SafeArea)", onClick: (BuildContext context) { - Navigator.of(context).push( MaterialPageRoute(builder: (BuildContext context) => CupertinoScreen())); + Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) => CupertinoScreen())); }, ) ]; @@ -46,6 +49,7 @@ class _Item extends StatelessWidget { final String title; _Item({this.title, this.onClick}); + @override Widget build(BuildContext context) { // TODO: implement build @@ -53,7 +57,7 @@ class _Item extends StatelessWidget { child: Card( child: Center(child: Text(title)), ), - onTap: (){ + onTap: () { onClick(context); }, ); diff --git a/example/lib/ui/screen/bilibili.dart b/example/lib/ui/screen/bilibili.dart index ea7c1793..f5476c65 100644 --- a/example/lib/ui/screen/bilibili.dart +++ b/example/lib/ui/screen/bilibili.dart @@ -15,15 +15,21 @@ class BiliBiliScreen extends StatefulWidget { } } -class _BiliBiliScreenState extends State with SingleTickerProviderStateMixin{ +class _BiliBiliScreenState extends State + with SingleTickerProviderStateMixin { RefreshController _refreshController; List items = []; void initData() { - - for (int i = 0; i < 55; i++) items.add(Container(child: Card(),height: 100.0,)); + for (int i = 0; i < 55; i++) + items.add(Container( + child: Card(), + height: 100.0, + )); } -TabController _tabController; + + TabController _tabController; + @override void initState() { // TODO: implement initState @@ -36,29 +42,48 @@ TabController _tabController; Widget build(BuildContext context) { // TODO: implement build return MaterialApp( - home:Scaffold( + home: Scaffold( body: RefreshConfiguration( child: SmartRefresher( - header: WaterDropMaterialHeader(backgroundColor: Colors.pink,), + header: WaterDropMaterialHeader( + backgroundColor: Colors.pink, + ), child: CustomScrollView( slivers: [ SliverAppBar( forceElevated: false, - leading: GestureDetector(child: Icon(Icons.add),onTap: (){ - Navigator.of(context).pop(); - },), + leading: GestureDetector( + child: Icon(Icons.add), + onTap: () { + Navigator.of(context).pop(); + }, + ), backgroundColor: Colors.pink, title: Text("哔哩哔哩"), actions: [Icon(Icons.verified_user)], ), SliverAppBar( flexibleSpace: FlexibleSpaceBar( - title: TabBar(tabs: [Tab(text: 'Tab1',),Tab(text: 'Tab2',),Tab(text: 'Tab3',),Tab(text: 'Tab1',)],controller: _tabController,), - + title: TabBar( + tabs: [ + Tab( + text: 'Tab1', + ), + Tab( + text: 'Tab2', + ), + Tab( + text: 'Tab3', + ), + Tab( + text: 'Tab1', + ) + ], + controller: _tabController, + ), ), pinned: true, leading: Container(), - ), SliverList(delegate: SliverChildListDelegate(items)) ], @@ -70,12 +95,14 @@ TabController _tabController; }); }, ), - headerOffset: MediaQuery.of(context).padding.top+56.0, + headerOffset: MediaQuery.of(context).padding.top + 56.0, ), ), - theme: ThemeData( brightness: Brightness.light, - primaryColor: Colors.white, //Changing this will change the color of the TabBar - ), + theme: ThemeData( + brightness: Brightness.light, + primaryColor: + Colors.white, //Changing this will change the color of the TabBar + ), ); } } diff --git a/example/lib/ui/screen/cupertinoScreen.dart b/example/lib/ui/screen/cupertinoScreen.dart index 69c539e7..9a4b82e8 100644 --- a/example/lib/ui/screen/cupertinoScreen.dart +++ b/example/lib/ui/screen/cupertinoScreen.dart @@ -14,12 +14,11 @@ class CupertinoScreen extends StatefulWidget { // TODO: implement createState return CupertinoScreenState(); } - } -class CupertinoScreenState extends State{ +class CupertinoScreenState extends State { + int _segIndex = 0; - int _segIndex =0 ; RefreshController _refreshController; @override @@ -28,6 +27,7 @@ class CupertinoScreenState extends State{ _refreshController = RefreshController(); super.initState(); } + @override void dispose() { // TODO: implement dispose @@ -46,67 +46,62 @@ class CupertinoScreenState extends State{ )); } return CupertinoApp( - home: CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - leading: GestureDetector( - child: Icon(Icons.arrow_back_ios), - onTap: (){ - Navigator.pop(context); - }, - ), - middle: CupertinoSegmentedControl( - children: {0:Text("sliver"),1:Text("refresher")}, - onValueChanged: (index) { - setState(() { - - }); - _segIndex = index; - }, - groupValue: _segIndex, - ), - ), - child: SafeArea( - child: Stack( - children: [ - Offstage( - offstage: _segIndex!=0, - child: RefreshConfiguration( - child: CustomScrollView( - physics: RefreshClampPhysics(springBackDistance: 100.0), - slivers: [ - MaterialClassicHeader.asSliver( - onRefresh: () async { - await Future.delayed(Duration(milliseconds: 400)); - return true; - }, - ), - - SliverList( - delegate: SliverChildListDelegate(widgets), - ), - ClassicFooter() - ], + navigationBar: CupertinoNavigationBar( + leading: GestureDetector( + child: Icon(Icons.arrow_back_ios), + onTap: () { + Navigator.pop(context); + }, + ), + middle: CupertinoSegmentedControl( + children: {0: Text("sliver"), 1: Text("refresher")}, + onValueChanged: (index) { + setState(() {}); + _segIndex = index; + }, + groupValue: _segIndex, + ), + ), + child: SafeArea( + child: Stack( + children: [ + Offstage( + offstage: _segIndex != 0, + child: RefreshConfiguration( + child: CustomScrollView( + physics: RefreshClampPhysics(springBackDistance: 100.0), + slivers: [ + MaterialClassicHeader.asSliver( + onRefresh: () async { + await Future.delayed(Duration(milliseconds: 400)); + return true; + }, ), - ), + SliverList( + delegate: SliverChildListDelegate(widgets), + ), + ClassicFooter() + ], ), - Offstage( - offstage: _segIndex!=1, - child: SmartRefresher( - - child: ListView(children:widgets), - controller: _refreshController, - header: ClassicHeader(), - onRefresh: (){ - Future.delayed(Duration(milliseconds: 1000)).whenComplete((){ - _refreshController.refreshCompleted(); - }); - }, - ), - ) - ], + ), ), - ), - )); + Offstage( + offstage: _segIndex != 1, + child: SmartRefresher( + child: ListView(children: widgets), + controller: _refreshController, + header: ClassicHeader(), + onRefresh: () { + Future.delayed(Duration(milliseconds: 1000)).whenComplete(() { + _refreshController.refreshCompleted(); + }); + }, + ), + ) + ], + ), + ), + )); } } diff --git a/example/lib/ui/screen/qqzone.dart b/example/lib/ui/screen/qqzone.dart index b153e7a6..d1d1cf67 100644 --- a/example/lib/ui/screen/qqzone.dart +++ b/example/lib/ui/screen/qqzone.dart @@ -6,24 +6,26 @@ import 'package:flutter/material.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; -class qqZone extends StatefulWidget{ - +class qqZone extends StatefulWidget { @override State createState() { // TODO: implement createState return _qqZoneState(); } - } -class _qqZoneState extends State{ +class _qqZoneState extends State { RefreshController _refreshController; List items = []; void initData() { - - for (int i = 0; i < 55; i++) items.add(Container(child: Card(),height: 100.0,)); + for (int i = 0; i < 55; i++) + items.add(Container( + child: Card(), + height: 100.0, + )); } + @override void initState() { // TODO: implement initState @@ -35,22 +37,30 @@ class _qqZoneState extends State{ Widget build(BuildContext context) { // TODO: implement build return MaterialApp( - home:Scaffold( + home: Scaffold( body: SmartRefresher( - header: MaterialClassicHeader(backgroundColor: Colors.blueAccent,distance: 80.0,), + header: MaterialClassicHeader( + backgroundColor: Colors.blueAccent, + distance: 80.0, + ), child: CustomScrollView( slivers: [ SliverAppBar( pinned: true, expandedHeight: 200.0, - leading: GestureDetector(child: Icon(Icons.arrow_back),onTap: (){ - Navigator.of(context).pop(); - },), + leading: GestureDetector( + child: Icon(Icons.arrow_back), + onTap: () { + Navigator.of(context).pop(); + }, + ), flexibleSpace: FlexibleSpaceBar( background: Container( - height: 100.0, - child: Image.asset("images/qqbg.jpg",fit: BoxFit.cover,) - ), + height: 100.0, + child: Image.asset( + "images/qqbg.jpg", + fit: BoxFit.cover, + )), ), backgroundColor: Colors.white, title: Text("QQ空间"), @@ -67,9 +77,11 @@ class _qqZoneState extends State{ }, ), ), - theme: ThemeData( brightness: Brightness.light, - primaryColor: Colors.white, //Changing this will change the color of the TabBar + theme: ThemeData( + brightness: Brightness.light, + primaryColor: + Colors.white, //Changing this will change the color of the TabBar ), ); } -} \ No newline at end of file +} diff --git a/example/lib/ui/test/Example1.dart b/example/lib/ui/test/Example1.dart index fd70ac2e..ede91fb6 100644 --- a/example/lib/ui/test/Example1.dart +++ b/example/lib/ui/test/Example1.dart @@ -19,10 +19,11 @@ class Example1State extends State { RefreshController _refreshController; ScrollController _scrollController; List data = []; + void _getDatas() { for (int i = 0; i < 4; i++) { data.add(Container( - color:Colors.greenAccent, + color: Colors.greenAccent, margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), child: Center( child: Text('Data $i'), @@ -40,8 +41,7 @@ class Example1State extends State { _refreshController.requestRefresh(); } - void _onOffsetCallback(bool isUp, double offset) { - } + void _onOffsetCallback(bool isUp, double offset) {} @override void initState() { @@ -55,35 +55,34 @@ class Example1State extends State { super.initState(); } - // Widget _footerCreate(BuildContext context,int mode){ // return new ClassicIndicator(mode: mode); // } @override Widget build(BuildContext context) { - return NestedScrollView( - key:PageStorageKey("q"), + return NestedScrollView( + key: PageStorageKey("q"), controller: _scrollController, headerSliverBuilder: (c, s) => [ - SliverPersistentHeader( - delegate: _SliverDelegate( - child: Container( - height: 300.0, - color: Colors.red, - ))), - SliverAppBar( - backgroundColor: Colors.greenAccent, - expandedHeight: 200.0, - pinned: true, - flexibleSpace: FlexibleSpaceBar( - centerTitle: true, - background: Image.network( - "https://images.unsplash.com/photo-1541701494587-cb58502866ab?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=0c21b1ac3066ae4d354a3b2e0064c8be&auto=format&fit=crop&w=500&q=60", - fit: BoxFit.cover, - )), - ), - ], + SliverPersistentHeader( + delegate: _SliverDelegate( + child: Container( + height: 300.0, + color: Colors.red, + ))), + SliverAppBar( + backgroundColor: Colors.greenAccent, + expandedHeight: 200.0, + pinned: true, + flexibleSpace: FlexibleSpaceBar( + centerTitle: true, + background: Image.network( + "https://images.unsplash.com/photo-1541701494587-cb58502866ab?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=0c21b1ac3066ae4d354a3b2e0064c8be&auto=format&fit=crop&w=500&q=60", + fit: BoxFit.cover, + )), + ), + ], body: Container( child: SmartRefresher( controller: _refreshController, @@ -91,8 +90,7 @@ class Example1State extends State { header: WaterDropHeader(), enablePullUp: true, onRefresh: () { - Future.delayed(const Duration(milliseconds: 2009)) - .then((val) { + Future.delayed(const Duration(milliseconds: 2009)).then((val) { data.add(Card( margin: EdgeInsets.only( left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), @@ -100,31 +98,29 @@ class Example1State extends State { child: Text('Data '), ), )); - if(mounted) - setState(() { - _refreshController.refreshCompleted(); - }); + if (mounted) + setState(() { + _refreshController.refreshCompleted(); + }); }); }, - onLoading: (){ - Future.delayed(const Duration(milliseconds: 2009)) - .then((val) { - if(mounted) - setState(() { - data.add(Card( - margin: EdgeInsets.only( - left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), - child: Center( - child: Text('Data '), - ), - )); - _refreshController.loadComplete(); - }); + onLoading: () { + Future.delayed(const Duration(milliseconds: 2009)).then((val) { + if (mounted) + setState(() { + data.add(Card( + margin: EdgeInsets.only( + left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), + child: Center( + child: Text('Data '), + ), + )); + _refreshController.loadComplete(); + }); }); }, onOffsetChange: _onOffsetCallback, child: ListView.builder( - itemExtent: 100.0, itemCount: data.length, itemBuilder: (context, index) => Item(), @@ -142,7 +138,7 @@ class _ItemState extends State { @override Widget build(BuildContext context) { return Card( - color:Colors.red, + color: Colors.red, margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), child: Center( child: Text('Data'), @@ -182,6 +178,4 @@ class _SliverDelegate extends SliverPersistentHeaderDelegate { // TODO: implement shouldRebuild return false; } - - } diff --git a/example/lib/ui/test/Example2.dart b/example/lib/ui/test/Example2.dart index 6986b772..4b6e32e6 100644 --- a/example/lib/ui/test/Example2.dart +++ b/example/lib/ui/test/Example2.dart @@ -13,7 +13,8 @@ class Example2 extends StatefulWidget { _Example2State createState() => _Example2State(); } -class _Example2State extends State with TickerProviderStateMixin ,AutomaticKeepAliveClientMixin{ +class _Example2State extends State + with TickerProviderStateMixin, AutomaticKeepAliveClientMixin { RefreshController _controller; int indexPage = 0; List data = []; @@ -29,8 +30,7 @@ class _Example2State extends State with TickerProviderStateMixin ,Auto for (var item in array) { data.add(item["image_url"]); } - if(mounted) - setState(() {}); + if (mounted) setState(() {}); _controller.loadComplete(); indexPage++; }).catchError((_) { @@ -56,7 +56,7 @@ class _Example2State extends State with TickerProviderStateMixin ,Auto child: Item( url: data[index], ), - onTap: (){ + onTap: () { _controller.requestRefresh(); }, ); @@ -103,7 +103,8 @@ class _Example2State extends State with TickerProviderStateMixin ,Auto onLoading: _onLoading, onOffsetChange: _onOffsetCallback, child: GridView.builder( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), itemCount: data.length, itemBuilder: buildImage, ), diff --git a/example/lib/ui/test/Example3.dart b/example/lib/ui/test/Example3.dart index ad683f83..f36e5317 100644 --- a/example/lib/ui/test/Example3.dart +++ b/example/lib/ui/test/Example3.dart @@ -11,7 +11,8 @@ class Example3 extends StatefulWidget { Example3State createState() => Example3State(); } -class Example3State extends State with AutomaticKeepAliveClientMixin,TickerProviderStateMixin { +class Example3State extends State + with AutomaticKeepAliveClientMixin, TickerProviderStateMixin { // RefreshMode refreshing = RefreshMode.idle; // LoadMode loading = LoadMode.idle; ValueNotifier topOffsetLis = ValueNotifier(0.0); @@ -19,23 +20,27 @@ class Example3State extends State with AutomaticKeepAliveClientMixin,T RefreshController _refreshController; ScrollController _scrollController; - List data = []; //test #68 - bool _enablePullUp=true,_enablePullDown=true; - + bool _enablePullUp = true, _enablePullDown = true; void _getDatas() { - data.add(Row(children: [ - FlatButton(onPressed: (){ - _refreshController.requestRefresh(); - }, child: Text("请求刷新")), - FlatButton(onPressed: (){ - _refreshController.requestLoading(); - }, child: Text("请求加载数据")) - ],)); - for (int i = 0; i < 3; i++) { + data.add(Row( + children: [ + FlatButton( + onPressed: () { + _refreshController.requestRefresh(); + }, + child: Text("请求刷新")), + FlatButton( + onPressed: () { + _refreshController.requestLoading(); + }, + child: Text("请求加载数据")) + ], + )); + for (int i = 0; i < 13; i++) { data.add(GestureDetector( child: Container( color: Color.fromARGB(255, 250, 250, 250), @@ -60,10 +65,7 @@ class Example3State extends State with AutomaticKeepAliveClientMixin,T void _onOffsetCallback(bool isUp, double offset) { // if you want change some widgets state ,you should rewrite the callback - if(mounted) - setState(() { - - }); + if (mounted) setState(() {}); if (isUp) { print(offset); bottomOffsetLis.value = offset; @@ -78,21 +80,15 @@ class Example3State extends State with AutomaticKeepAliveClientMixin,T // TODO: implement initState // for test #68 true-> false ->true - Future.delayed(Duration(milliseconds: 3000),(){ + Future.delayed(Duration(milliseconds: 3000), () { _enablePullDown = false; _enablePullUp = false; - if(mounted) - setState(() { - - }); + if (mounted) setState(() {}); }); - Future.delayed(Duration(milliseconds: 6000),(){ + Future.delayed(Duration(milliseconds: 6000), () { _enablePullDown = true; _enablePullUp = true; - if(mounted) - setState(() { - - }); + if (mounted) setState(() {}); }); // // for test #68 false-> true ->false @@ -151,16 +147,17 @@ class Example3State extends State with AutomaticKeepAliveClientMixin,T Widget build(BuildContext context) { return SmartRefresher( enablePullUp: true, - enablePullDown: false, + enablePullDown: true, controller: _refreshController, - header: ClassicHeader(iconPos: IconPosition.bottom,), + header: MaterialClassicHeader( + ), onRefresh: () { print("onRefresh"); - data.add(Container(child: Card(),height: 100.0,)); - if(mounted) - setState(() { - - }); + data.add(Container( + child: Card(), + height: 100.0, + )); + if (mounted) setState(() {}); _refreshController.refreshFailed(); // Future.delayed(const Duration(milliseconds: 2009)).then((val) { //// data.add(Card()); @@ -168,9 +165,9 @@ class Example3State extends State with AutomaticKeepAliveClientMixin,T // }); }, child: Container( - height: 695.0, + height: 395.0, child: PageView( - children: [Text("第一页"),Text("第二页"),Text("第三页")], + children: [Text("第一页"), Text("第二页"), Text("第三页")], ), ), onLoading: () { @@ -178,9 +175,8 @@ class Example3State extends State with AutomaticKeepAliveClientMixin,T Future.delayed(const Duration(milliseconds: 2000)).then((val) { data.add(Card()); - if(mounted) - setState(() {}); - _refreshController.loadFailed(); + if (mounted) setState(() {}); + _refreshController.loadComplete(); }); }, ); @@ -188,7 +184,7 @@ class Example3State extends State with AutomaticKeepAliveClientMixin,T @override // TODO: implement wantKeepAlive - bool get wantKeepAlive => false; + bool get wantKeepAlive => true; } class CirclePainter extends CustomClipper { diff --git a/example/lib/ui/test/Example4.dart b/example/lib/ui/test/Example4.dart index 6848d8b1..db8fa00a 100644 --- a/example/lib/ui/test/Example4.dart +++ b/example/lib/ui/test/Example4.dart @@ -1,8 +1,9 @@ import 'dart:async'; import 'package:example/other/RunningHeader.dart'; -import 'package:flutter/material.dart' hide RefreshIndicator,RefreshIndicatorState; -import 'package:pull_to_refresh/pull_to_refresh.dart' ; +import 'package:flutter/material.dart' + hide RefreshIndicator, RefreshIndicatorState; +import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:flutter/cupertino.dart'; class Example4 extends StatefulWidget { @@ -59,8 +60,7 @@ class _Example4State extends State with TickerProviderStateMixin { @override Widget build(BuildContext context) { return CustomScrollView( - physics:RefreshBouncePhysics() - , + physics: RefreshBouncePhysics(), slivers: [ _enablePullDown ? RunningHeader.asSliver(onRefresh: () async { @@ -74,7 +74,7 @@ class _Example4State extends State with TickerProviderStateMixin { ? ClassicFooter.asSliver(onLoading: () async { await Future.delayed(Duration(milliseconds: 400)); //return true it mean set the footerStatus to idle,else set to NoData state - return true; + return 0; }) : null ].where((child) => child != null).toList(), @@ -82,7 +82,6 @@ class _Example4State extends State with TickerProviderStateMixin { } } - class _SliverDelegate extends SliverPersistentHeaderDelegate { final Widget child; diff --git a/example/lib/ui/test/TestPage.dart b/example/lib/ui/test/TestPage.dart index e24b0445..8cde9438 100644 --- a/example/lib/ui/test/TestPage.dart +++ b/example/lib/ui/test/TestPage.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; class TestPage extends StatefulWidget { TestPage({Key key, this.title}) : super(key: key); + // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect // how it looks. @@ -21,19 +22,19 @@ class TestPage extends StatefulWidget { _TestPageState createState() => new _TestPageState(); } -class _TestPageState extends State with SingleTickerProviderStateMixin{ +class _TestPageState extends State + with SingleTickerProviderStateMixin { int tabIndex = 0; PageController _pageController; List views; TabController _tabController; - GlobalKey example3Key= GlobalKey(); - GlobalKey example1Key= GlobalKey(); + GlobalKey example3Key = GlobalKey(); + GlobalKey example1Key = GlobalKey(); - void _changePage(){ + void _changePage() { Navigator.of(context).pushNamed("sec"); } - @override Widget build(BuildContext context) { // This method is rerun every time setState is called, for instance as done @@ -57,47 +58,44 @@ class _TestPageState extends State with SingleTickerProviderStateMixin // ), // body: new TabBarView(children: views,controller:_tabController ,), // ); - return Column( + return Column( children: [ - Expanded( - - child: PageView( - controller: _pageController , + Expanded( + child: PageView( + controller: _pageController, physics: NeverScrollableScrollPhysics(), - children: views,onPageChanged: (index){ - tabIndex = index; - if(mounted) - setState(() { - - }); - }, - ), - ), + children: views, + onPageChanged: (index) { + tabIndex = index; + if (mounted) setState(() {}); + }, + ), + ), BottomNavigationBar( items: [ BottomNavigationBarItem( - icon: Icon(Icons.home, + icon: Icon(Icons.home, color: tabIndex == 0 ? Colors.blue : Colors.grey), - title: Text('Example1', - style: TextStyle( + title: Text('Example1', + style: TextStyle( color: tabIndex == 0 ? Colors.blue : Colors.grey))), BottomNavigationBarItem( - icon: Icon(Icons.cloud, + icon: Icon(Icons.cloud, color: tabIndex == 1 ? Colors.blue : Colors.grey), - title: Text('Example2', - style: TextStyle( + title: Text('Example2', + style: TextStyle( color: tabIndex == 1 ? Colors.blue : Colors.grey))), BottomNavigationBarItem( - icon: Icon(Icons.call, + icon: Icon(Icons.call, color: tabIndex == 2 ? Colors.blue : Colors.grey), - title: Text('Example3', - style: TextStyle( + title: Text('Example3', + style: TextStyle( color: tabIndex == 2 ? Colors.blue : Colors.grey))), BottomNavigationBarItem( - icon: Icon(Icons.transform, + icon: Icon(Icons.transform, color: tabIndex == 3 ? Colors.blue : Colors.grey), - title: Text('Example4', - style: TextStyle( + title: Text('Example4', + style: TextStyle( color: tabIndex == 3 ? Colors.blue : Colors.grey))), ], onTap: (index) { @@ -114,10 +112,14 @@ class _TestPageState extends State with SingleTickerProviderStateMixin @override void initState() { // TODO: implement initState - _tabController = TabController(length: 4, vsync: this); + _tabController = TabController(length: 4, vsync: this); _pageController = PageController(); - views = [ Example1(key:example1Key), Example2(), Example3(key:example3Key), Example4()]; + views = [ + Example1(key: example1Key), + Example2(), + Example3(key: example3Key), + Example4() + ]; super.initState(); } - } diff --git a/lib/pull_to_refresh.dart b/lib/pull_to_refresh.dart index 135e25b9..b24b48b5 100644 --- a/lib/pull_to_refresh.dart +++ b/lib/pull_to_refresh.dart @@ -12,4 +12,4 @@ export 'src/indicator/waterdrop_header.dart'; export 'src/indicator/custom_indicator.dart'; export 'src/internals/refresh_physics.dart'; export "src/internals/indicator_wrap.dart"; -export 'src/indicator/material_indicator.dart'; \ No newline at end of file +export 'src/indicator/material_indicator.dart'; diff --git a/lib/src/indicator/classic_indicator.dart b/lib/src/indicator/classic_indicator.dart index e2572ad9..05b8aae5 100644 --- a/lib/src/indicator/classic_indicator.dart +++ b/lib/src/indicator/classic_indicator.dart @@ -265,7 +265,7 @@ class _ClassicFooterState extends LoadIndicatorState { ? TextDirection.ltr : TextDirection.rtl, direction: widget.iconPos == IconPosition.bottom || - widget.iconPos == IconPosition.top + widget.iconPos == IconPosition.top ? Axis.vertical : Axis.horizontal, crossAxisAlignment: WrapCrossAlignment.center, diff --git a/lib/src/indicator/custom_indicator.dart b/lib/src/indicator/custom_indicator.dart index 62ecc3c1..c0c6d417 100644 --- a/lib/src/indicator/custom_indicator.dart +++ b/lib/src/indicator/custom_indicator.dart @@ -70,10 +70,7 @@ class CustomFooter extends LoadIndicator { @required this.builder, @required OnLoading onLoading, Function onClick, - }) : super( - key: key, - onLoading: onLoading, - onClick: onClick); + }) : super(key: key, onLoading: onLoading, onClick: onClick); @override State createState() { diff --git a/lib/src/internals/indicator_wrap.dart b/lib/src/internals/indicator_wrap.dart index 42ca39ed..3009d528 100644 --- a/lib/src/internals/indicator_wrap.dart +++ b/lib/src/internals/indicator_wrap.dart @@ -4,13 +4,15 @@ createTime:2018-05-14 15:39 */ +import 'package:flutter/rendering.dart'; +import 'package:flutter/semantics.dart'; import 'package:flutter/widgets.dart'; import 'dart:math' as math; import '../smart_refresher.dart'; import 'slivers.dart'; typedef OnRefresh = Future Function(); -typedef OnLoading = Future Function(); +typedef OnLoading = Future Function(); const int default_completeDuration = 500; @@ -235,6 +237,14 @@ abstract class LoadIndicatorState extends State return overscrollPastEnd; } + bool _checkIfCanLoading() { + return _position.extentAfter <= configuration.footerTriggerDistance && + configuration.autoLoad && + _enableLoadingAgain && + _position.extentBefore > 0.0 && + mode == LoadStatus.idle; + } + void _handleModeChange() { if (!mounted || _isHide) { return; @@ -245,8 +255,10 @@ abstract class LoadIndicatorState extends State refresher.widget.onLoading(); } else if (widget.onLoading != null) { widget.onLoading().then((result) { - if (result) { + if (result == 0) { mode = LoadStatus.idle; + } else if (result == 1) { + mode = LoadStatus.failed; } else { mode = LoadStatus.noMore; } @@ -258,13 +270,13 @@ abstract class LoadIndicatorState extends State void _dispatchModeByOffset(double offset) { // avoid trigger more time when user dragging in the same direction - if (_position.activity is! DragScrollActivity &&_position.userScrollDirection.index == 2 && - _position.extentAfter <= configuration.footerTriggerDistance && - configuration.autoLoad && - _enableLoadingAgain && - mode == LoadStatus.idle) { - mode = LoadStatus.loading; - _enableLoadingAgain = false; + if (_checkIfCanLoading()) { + if (_position.activity is BallisticScrollActivity || + _position.activity is DrivenScrollActivity) { + // DrivenScrollActivity mostly scrollPosition.animateTo + mode = LoadStatus.loading; + _enableLoadingAgain = false; + } } } @@ -277,6 +289,12 @@ abstract class LoadIndicatorState extends State void _listenScrollEnd() { if (!_position.isScrollingNotifier.value) { + // when user release gesture from screen + if (_checkIfCanLoading()) { + if (_position.activity is IdleScrollActivity) { + mode = LoadStatus.loading; + } + } _enableLoadingAgain = true; } } @@ -304,8 +322,9 @@ abstract class LoadIndicatorState extends State _isHide = cons.biggest.height == 0.0; return GestureDetector( onTap: () { - if (configuration.clickLoadingWhenIdle||_mode.value == LoadStatus.failed) { - _mode.value = LoadStatus.loading; + if (configuration.clickLoadingWhenIdle || + _mode.value == LoadStatus.failed) { + mode = LoadStatus.loading; } if (widget.onClick != null) { widget.onClick(); @@ -365,7 +384,7 @@ mixin IndicatorStateMixin on State { void _updateListener() { configuration = RefreshConfiguration.of(context); assert(configuration != null, - "when use asSliver ,please wrap scrollView in RefreshConfiguration!"); + "when use asSliver ,please wrap scrollView in RefreshConfiguration!"); refresher = SmartRefresher.of(context); ValueNotifier newMode; if (refresher == null) { diff --git a/lib/src/internals/refresh_physics.dart b/lib/src/internals/refresh_physics.dart index b8f8a179..a79f8f76 100644 --- a/lib/src/internals/refresh_physics.dart +++ b/lib/src/internals/refresh_physics.dart @@ -32,13 +32,15 @@ class RefreshClampPhysics extends ScrollPhysics { final double springBackDistance; /// Creates scroll physics that bounce back from the edge. - const RefreshClampPhysics({ScrollPhysics parent, this.springBackDistance:100.0}) + const RefreshClampPhysics( + {ScrollPhysics parent, this.springBackDistance: 100.0}) : super(parent: parent); @override RefreshClampPhysics applyTo(ScrollPhysics ancestor) { return RefreshClampPhysics( - parent: buildParent(ancestor), springBackDistance: this.springBackDistance); + parent: buildParent(ancestor), + springBackDistance: this.springBackDistance); } @override @@ -50,30 +52,26 @@ class RefreshClampPhysics extends ScrollPhysics { @override double applyPhysicsToUserOffset(ScrollMetrics position, double offset) { // TODO: implement applyPhysicsToUserOffset - final ScrollPosition scrollPosition = - position as ScrollPosition; - if (position.extentBefore < springBackDistance ) { - final double newPixels = position.pixels-offset*0.5; - - if(scrollPosition.userScrollDirection.index==2){ - if(newPixels>springBackDistance){ - return position.pixels-springBackDistance; - } - else{ - return offset*0.5; + final ScrollPosition scrollPosition = position as ScrollPosition; + if (position.extentBefore < springBackDistance) { + final double newPixels = position.pixels - offset * 0.5; + + if (scrollPosition.userScrollDirection.index == 2) { + if (newPixels > springBackDistance) { + return position.pixels - springBackDistance; + } else { + return offset * 0.5; } } - return offset*0.5; + return offset * 0.5; } return super.applyPhysicsToUserOffset(position, offset); } @override double applyBoundaryConditions(ScrollMetrics position, double value) { - final ScrollPosition scrollPosition = - position as ScrollPosition; - if(scrollPosition.extentBefore position.pixels) { @@ -97,14 +95,15 @@ class RefreshClampPhysics extends ScrollPhysics { if (value < position.minScrollExtent && position.minScrollExtent < position.pixels) // hit top edge return value - position.minScrollExtent; - if (position.maxScrollExtent <= position.pixels && position.pixels < value) // overscroll + if (position.maxScrollExtent <= position.pixels && + position.pixels < value) // overscroll return value - position.pixels; - if (position.pixels < position.maxScrollExtent && position.maxScrollExtent < value) // hit bottom edge + if (position.pixels < position.maxScrollExtent && + position.maxScrollExtent < value) // hit bottom edge return value - position.maxScrollExtent; return 0.0; } - @override Simulation createBallisticSimulation( ScrollMetrics position, double velocity) { @@ -118,11 +117,12 @@ class RefreshClampPhysics extends ScrollPhysics { tolerance: tolerance, ); } - if(velocity.abs()<=tolerance.velocity.abs())return null; + if (velocity.abs() <= tolerance.velocity.abs()) return null; return RefreshClampingSimulation( position: position.pixels, velocity: velocity, - extentBefore:velocity<0?position.extentBefore-springBackDistance:-1.0, + extentBefore: + velocity < 0 ? position.extentBefore - springBackDistance : -1.0, tolerance: tolerance, ); } @@ -136,24 +136,26 @@ class RefreshClampingSimulation extends ClampingScrollSimulation { this.extentBefore, double friction = 0.015, Tolerance tolerance = Tolerance.defaultTolerance, - }) : assert(_flingVelocityPenetration(0.0) == _initialVelocityPenetration), - super(tolerance: tolerance,position:position,velocity:velocity,friction:friction) { - if(extentBefore!=-1.0) { + }) : assert(_flingVelocityPenetration(0.0) == _initialVelocityPenetration), + super( + tolerance: tolerance, + position: position, + velocity: velocity, + friction: friction) { + if (extentBefore != -1.0) { _duration = _flingDuration(velocity); _distance = math.min( (velocity * _duration / _initialVelocityPenetration).abs(), extentBefore); if (_distance == extentBefore) { - _duration = _distance/1000; + _duration = _distance / 1000; } - } - else{ + } else { _duration = _flingDuration(velocity); - _distance = - (velocity * _duration / _initialVelocityPenetration).abs(); + _distance = (velocity * _duration / _initialVelocityPenetration).abs(); } - } + final double extentBefore; double _duration; double _distance; @@ -170,7 +172,8 @@ class RefreshClampingSimulation extends ClampingScrollSimulation { final double scaledFriction = friction * _decelerationForFriction(0.84); // See getSplineDeceleration(). - final double deceleration = math.log(0.35 * velocity.abs() / scaledFriction); + final double deceleration = + math.log(0.35 * velocity.abs() / scaledFriction); return math.exp(deceleration / (_kDecelerationRate - 1.0)); } @@ -191,8 +194,11 @@ class RefreshClampingSimulation extends ClampingScrollSimulation { // f(t) = (1165.03 t^3 - 3143.62 t^2 + 2945.87 t) / 961.0 // = 1.2 t^3 - 3.27 t^2 + 3.065 t static const double _initialVelocityPenetration = 3.065; + static double _flingDistancePenetration(double t) { - return (1.2 * t * t * t) - (3.27 * t * t) + (_initialVelocityPenetration * t); + return (1.2 * t * t * t) - + (3.27 * t * t) + + (_initialVelocityPenetration * t); } // The derivative of the _flingDistancePenetration() function. @@ -212,9 +218,8 @@ class RefreshClampingSimulation extends ClampingScrollSimulation { return _distance * _flingVelocityPenetration(t) * velocity.sign / _duration; } - @override bool isDone(double time) { return time >= _duration; } -} \ No newline at end of file +} diff --git a/lib/src/internals/slivers.dart b/lib/src/internals/slivers.dart index d25ecf9f..a3359477 100644 --- a/lib/src/internals/slivers.dart +++ b/lib/src/internals/slivers.dart @@ -279,18 +279,18 @@ class _RenderSliverLoading extends RenderSliverSingleBoxAdapter { // visually. final double layoutExtentOffsetCompensation = 0.0; - bool _computeIfFull(SliverConstraints cons){ + bool _computeIfFull(SliverConstraints cons) { final RenderViewport viewport = parent; RenderSliver sliverP = viewport.firstChild; double totalScrollExtent = cons.precedingScrollExtent; - while(sliverP!=this){ - if(sliverP is _RenderSliverRefresh){ - totalScrollExtent-=sliverP.geometry.scrollExtent; + while (sliverP != this) { + if (sliverP is _RenderSliverRefresh) { + totalScrollExtent -= sliverP.geometry.scrollExtent; break; } sliverP = viewport.childAfter(sliverP); } - return totalScrollExtent>=cons.viewportMainAxisExtent; + return totalScrollExtent >= cons.viewportMainAxisExtent; } @override @@ -302,7 +302,6 @@ class _RenderSliverLoading extends RenderSliverSingleBoxAdapter { } bool active; if (hideWhenNotFull) { - active = _computeIfFull(constraints); } else { active = true; diff --git a/lib/src/smart_refresher.dart b/lib/src/smart_refresher.dart index e8a40aed..18e72391 100644 --- a/lib/src/smart_refresher.dart +++ b/lib/src/smart_refresher.dart @@ -17,7 +17,7 @@ typedef IndicatorBuilder = Widget Function(); enum RefreshStatus { idle, canRefresh, refreshing, completed, failed } -enum LoadStatus { idle, loading, noMore,failed } +enum LoadStatus { idle, loading, noMore, failed } enum RefreshStyle { Follow, UnFollow, Behind, Front } @@ -71,7 +71,8 @@ class SmartRefresher extends StatefulWidget { SmartRefresherState createState() => SmartRefresherState(); static SmartRefresherState of(BuildContext context) { - return context.ancestorStateOfType(const TypeMatcher() ) ; + return context + .ancestorStateOfType(const TypeMatcher()); } } @@ -87,10 +88,9 @@ class SmartRefresherState extends State { final child = widget.child; final Widget defaultFooter = ClassicFooter(); _configuration = RefreshConfiguration.of(context); - if(child!=null&&child is ScrollView&&child.controller!=null){ + if (child != null && child is ScrollView && child.controller != null) { widget.controller.scrollController = child.controller; - } - else{ + } else { widget.controller.scrollController = PrimaryScrollController.of(context); } @@ -113,10 +113,12 @@ class SmartRefresherState extends State { widget.controller._triggerDistance = _header.refreshStyle == RefreshStyle.Front ? 0.0 - : -(_configuration==null?80.0:_configuration.headerTriggerDistance); + : -(_configuration == null + ? 80.0 + : _configuration.headerTriggerDistance); } - void onPositionUpdated(ScrollPosition newPosition){ + void onPositionUpdated(ScrollPosition newPosition) { widget.controller.position = newPosition; } @@ -124,7 +126,7 @@ class SmartRefresherState extends State { void initState() { // TODO: implement initState super.initState(); - if (widget.controller.initialRefresh&&widget.enablePullDown) { + if (widget.controller.initialRefresh && widget.enablePullDown) { WidgetsBinding.instance.addPostFrameCallback((_) { widget.controller.requestRefresh(); }); @@ -166,15 +168,15 @@ class SmartRefresherState extends State { final Widget child = widget.child; List slivers; Widget body; - if(child is ScrollView) { + if (child is ScrollView) { if (widget.child is BoxScrollView) { //avoid system inject padding when own indicator top or bottom - Widget sliver = (widget.child as BoxScrollView).buildChildLayout( - context); + Widget sliver = + (widget.child as BoxScrollView).buildChildLayout(context); EdgeInsets effectPadding = (widget.child as BoxScrollView).padding; if (effectPadding == null) { - final MediaQueryData mediaQuery = MediaQuery.of( - context, nullOk: true); + final MediaQueryData mediaQuery = + MediaQuery.of(context, nullOk: true); if (mediaQuery != null) { effectPadding = mediaQuery.padding.copyWith( left: 0.0, @@ -193,10 +195,10 @@ class SmartRefresherState extends State { sliver = SliverPadding(padding: effectPadding, sliver: sliver); } slivers = [sliver]; - } else { + } else { slivers = List.from(child.buildSlivers(context), growable: true); } - body = CustomScrollView( + body = CustomScrollView( physics: _getScrollPhysics(), controller: widget.controller.scrollController, cacheExtent: child?.cacheExtent, @@ -205,13 +207,15 @@ class SmartRefresherState extends State { slivers: slivers, reverse: child?.reverse, ); - } - else{ - slivers = [SliverToBoxAdapter(child: child ?? Container(),)]; - body = CustomScrollView( + } else { + slivers = [ + SliverToBoxAdapter( + child: child ?? Container(), + ) + ]; + body = CustomScrollView( physics: _getScrollPhysics(), controller: widget.controller.scrollController, - key: widget.child?.key, slivers: slivers, ); } @@ -238,7 +242,8 @@ class SmartRefresherState extends State { class RefreshController { ValueNotifier headerMode = ValueNotifier(RefreshStatus.idle); ValueNotifier footerMode = ValueNotifier(LoadStatus.idle); - @Deprecated('use position instead,jumpTo and animateTo will lead to refresh together with mutiple ScrollView depend on the same ScrollController') + @Deprecated( + 'use position instead,jumpTo and animateTo will lead to refresh together with mutiple ScrollPositions which depending on the same ScrollController') ScrollController scrollController; ScrollPosition position; double _triggerDistance; @@ -260,9 +265,8 @@ class RefreshController { Curve curve: Curves.linear}) { assert(position != null, 'Try not to call requestRefresh() before build,please call after the ui was rendered'); - if(isRefresh)return; - position?.animateTo(_triggerDistance, - duration: duration, curve: curve); + if (isRefresh) return; + position?.animateTo(_triggerDistance, duration: duration, curve: curve); } void requestLoading( @@ -270,21 +274,18 @@ class RefreshController { Curve curve: Curves.linear}) { assert(position != null, 'Try not to call requestLoading() before build,please call after the ui was rendered'); - if(isLoading)return; - position - ?.animateTo(position.maxScrollExtent, - duration: duration, curve: curve) - ; + if (isLoading) return; + position?.animateTo(position.maxScrollExtent, + duration: duration, curve: curve); } - void refreshCompleted({bool resetFooterState:false}) { + void refreshCompleted({bool resetFooterState: false}) { headerMode?.value = RefreshStatus.completed; - if(resetFooterState){ + if (resetFooterState) { resetNoData(); } } - void refreshFailed() { headerMode?.value = RefreshStatus.failed; } @@ -359,7 +360,6 @@ class RefreshConfiguration extends InheritedWidget { @override bool updateShouldNotify(RefreshConfiguration oldWidget) { - print(this==oldWidget); return autoLoad != oldWidget.autoLoad || skipCanRefresh != oldWidget.skipCanRefresh || hideFooterWhenNotFull != oldWidget.hideFooterWhenNotFull || diff --git a/pubspec.yaml b/pubspec.yaml index f965080c..59679779 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.4.3 +version: 1.4.4 author: Jpeng homepage: https://github.com/peng8350/flutter_pulltorefresh