flutter_easyrefresh 是一個下拉刷新上拉加載的插件,具體我就不介紹了,這裏主要是解決flutter_easyrefresh的bug,主要我在用此插件的時候遇到如下兩個問題:
①.上拉加載最後的footer不消失
②.加載少量數據出現多次加載現象解決方案
如下是問題及解決過程,如果想直接看最終解決方案請拉到最後面有最終版本
第一個問題現象如下,就是加載過程中在數據不能佔滿整個界面的時候footer是不會自動消失的
解決方案:加載完成延時一秒將onLoad置爲false即可,即footer不會繼續顯示。
在onLoad的地方添加isFooter用來控制footer是否顯示
onLoad: _isFooter
? () async {
await Future.delayed(Duration(seconds: 0), () {
print('onLoad');
setState(() {
_count += 1;
});
_controller.finishLoad(noMore: _count >= 10);
loadingBottomControl();
});
}
: null,
下面的邏輯是加載完成一秒後讓其不顯示
void loadingBottomControl() {
Future.delayed(Duration(milliseconds: 1000), () {
setState(() {
_isFooter = false;
Future.delayed(Duration(milliseconds: 1000), () {
setState(() {
_isFooter = true;
});
});
});
});
}
最後別忘了添加變量
bool _isFooter = true;
以上代碼即可解決第一個問題,但是當加載較少的數據時會出現多次加載現象,解決方案:
監聽當前界面事件,讓其在一次點擊後只能刷新一次,注意此處不能用GestureDetector,因爲GestureDetector只能監聽純單擊,不能監聽滑動的點擊,此處我們用的是Listener,解決方案如下:
bool _isLoad = false;//防止load多次加載
Listener(
onPointerDown: (p) {
setState(() {
_isLoad = true;//設置成true,可以加載
print("onPointerDown$_isLoad");
});
},
child: EasyRefresh.custom(
enableControlFinishRefresh: false,
enableControlFinishLoad: true,
controller: _controller,
header: ClassicalHeader(),
footer: ClassicalFooter(),
onRefresh: () async {
await Future.delayed(Duration(seconds: 0), () {
print('onRefresh');
setState(() {
_count = 1;
});
_controller.resetLoadState();
});
},
onLoad: _isFooter
? () async {
await Future.delayed(Duration(seconds: 0), () {
print('onLoad');
print("onLoad$_isLoad");
if (_isLoad) {
_isLoad = false;//設置成false,防止多次加載
setState(() {
_count += 1;
});
_controller.finishLoad(noMore: _count >= 10);
loadingBottomControl();
} else {
_controller.finishLoad();
}
});
}
: null,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
width: 60.0,
height: 60.0,
child: Center(
child: Text('$index'),
),
color: index % 2 == 0
? Colors.grey[300]
: Colors.transparent,
);
},
childCount: _count,
),
),
],
),
)
如上可以解決多次加載問題,但是會出現上拉不放底部加載完成閃爍問題,解決方案如下:
Listener(
onPointerDown: (p) {
setState(() {
_isLoad = true;
_isFooter = true;//在點擊過後才讓其顯示
print("onPointerDown$_isLoad");
});
},
child: EasyRefresh.custom(
enableControlFinishRefresh: false,
enableControlFinishLoad: true,
controller: _controller,
header: ClassicalHeader(),
footer: ClassicalFooter(),
onRefresh: () async {
await Future.delayed(Duration(seconds: 0), () {
print('onRefresh');
setState(() {
_count = 1;
});
_controller.resetLoadState();
});
},
onLoad: _isFooter
? () async {
await Future.delayed(Duration(seconds: 0), () {
print('onLoad');
print("onLoad$_isLoad");
if (_isLoad) {
_isLoad = false;
setState(() {
_count += 1;
});
_controller.finishLoad(noMore: _count >= 10);
loadingBottomControl();
} else {
_controller.finishLoad();
}
});
}
: null,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
width: 60.0,
height: 60.0,
child: Center(
child: Text('$index'),
),
color: index % 2 == 0
? Colors.grey[300]
: Colors.transparent,
);
},
childCount: _count,
),
),
],
),
));
//此處修改爲不顯示isFooter
void loadingBottomControl() {
Future.delayed(Duration(milliseconds: 1000), () {
setState(() {
_isFooter = false;
});
});
}
由於上述代碼在一秒後就隱藏footer,感覺效果不好,作如下修改:
bool _isFooter = true;//控制footer是否顯示
bool _isLoad = false;//防止load多次加載
bool _isMove = false;//防止load多次加載
bool _isAutoClose = false;//是否是一秒後自動關閉footer
Listener(
onPointerDown: (p) {
setState(() {
_isLoad = true;
_isFooter = true;
print("onPointerDown$_isLoad");
});
},
onPointerMove: (p){
setState(() {
_isMove = true;
});
},
onPointerUp: (p){
_isMove = false;
if(!_isAutoClose) {
setState(() {
_isAutoClose = true;
_isFooter = false;
});
}
},
child: EasyRefresh.custom(
enableControlFinishRefresh: false,
enableControlFinishLoad: true,
controller: _controller,
header: ClassicalHeader(),
footer: ClassicalFooter(),
onRefresh: () async {
await Future.delayed(Duration(seconds: 0), () {
print('onRefresh');
setState(() {
_count = 1;
});
_controller.resetLoadState();
});
},
onLoad: _isFooter
? () async {
await Future.delayed(Duration(seconds: 0), () {
print('onLoad');
print("onLoad$_isLoad");
if (_isLoad) {
_isLoad = false;
setState(() {
_count += 1;
});
_controller.finishLoad(noMore: _count >= 10);
loadingBottomControl();
} else {
_controller.finishLoad();
}
});
}
: null,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
width: 60.0,
height: 60.0,
child: Center(
child: Text('$index'),
),
color: index % 2 == 0
? Colors.grey[300]
: Colors.transparent,
);
},
childCount: _count,
),
),
],
),
)
void loadingBottomControl() {
Future.delayed(Duration(milliseconds: 1000), () {
setState(() {
if(_isMove) {
_isAutoClose = false;
} else {
_isAutoClose = true;
_isFooter = false;
}
});
});
}
最後附上全部代碼:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
// App名字
title: 'EasyRefresh',
// App主題
theme: new ThemeData(
primarySwatch: Colors.orange,
),
// 主頁
home: _Example(),
localizationsDelegates: [
GlobalEasyRefreshLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
);
}
}
class _Example extends StatefulWidget {
@override
_ExampleState createState() {
return _ExampleState();
}
}
class _ExampleState extends State<_Example> {
EasyRefreshController _controller;
// 條目總數
int _count = 1;
bool _isFooter = true;//控制footer是否顯示
bool _isLoad = false;//防止load多次加載
bool _isMove = false;//防止load多次加載
bool _isAutoClose = false;//是否是一秒後自動關閉footer
@override
void initState() {
super.initState();
_controller = EasyRefreshController();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("EasyRefresh"),
),
body: Listener(
onPointerDown: (p) {
setState(() {
_isLoad = true;
_isFooter = true;
print("onPointerDown$_isLoad");
});
},
onPointerMove: (p){
setState(() {
_isMove = true;
});
},
onPointerUp: (p){
_isMove = false;
if(!_isAutoClose) {
setState(() {
_isAutoClose = true;
_isFooter = false;
});
}
},
child: EasyRefresh.custom(
enableControlFinishRefresh: false,
enableControlFinishLoad: true,
controller: _controller,
header: ClassicalHeader(),
footer: ClassicalFooter(),
onRefresh: () async {
await Future.delayed(Duration(seconds: 0), () {
print('onRefresh');
setState(() {
_count = 1;
});
_controller.resetLoadState();
});
},
onLoad: _isFooter
? () async {
await Future.delayed(Duration(seconds: 0), () {
print('onLoad');
print("onLoad$_isLoad");
if (_isLoad) {
_isLoad = false;
setState(() {
_count += 1;
});
_controller.finishLoad(noMore: _count >= 10);
loadingBottomControl();
} else {
_controller.finishLoad();
}
});
}
: null,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
width: 60.0,
height: 60.0,
child: Center(
child: Text('$index'),
),
color: index % 2 == 0
? Colors.grey[300]
: Colors.transparent,
);
},
childCount: _count,
),
),
],
),
));
}
void loadingBottomControl() {
Future.delayed(Duration(milliseconds: 1000), () {
setState(() {
if(_isMove) {
_isAutoClose = false;
} else {
_isAutoClose = true;
_isFooter = false;
}
});
});
}
}
上面的代碼是嵌套到界面內部的,下面是直接包裝到EasyRefresh中,直接調用即可:
以下是最終版本!!!其中用到了高級函數和擴展函數特性,需要flutter dev分支或者flutter master分支並且dart版本是2.6以上,以後可能會放到flutter stable分支中,當下測試還是不能使用在stable分支和beta分支中,如果不想用master或者dev版本只能用上面的方案了!
import 'package:flutter/widgets.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
//此處是將包裝方法封裝到EasyRefresh 中
extension SmartRefresh on EasyRefresh {
static bool _isFooter = true; //控制footer是否顯示
static bool _isLoad = false; //防止load多次加載
static bool _isMove = false; //防止load多次加載
static bool _isAutoClose = false; //是否是一秒後自動關閉footer
Listener buildSmartRefresh(State state) {
return Listener(
onPointerDown: (p) {
state.setState(() {
_isLoad = true;
_isFooter = true;
print("onPointerDown$_isLoad");
});
},
onPointerMove: (p) {
state.setState(() {
_isMove = true;
});
},
onPointerUp: (p) {
_isMove = false;
if (!_isAutoClose) {
state.setState(() {
_isAutoClose = true;
_isFooter = false;
});
}
},
child: this,
);
}
Function onSmartRefreshCallback(onRefresh,EasyRefreshController controller) {
return () async {
await Future.delayed(Duration(seconds: 0), () {
onRefresh();
controller.resetLoadState();
});
};
}
Function onSmartLoadCallback(onLoad,state,EasyRefreshController controller) {
return _isFooter
? () async {
await Future.delayed(Duration(seconds: 0), () {
print('onLoad');
print("onLoad$_isLoad");
if (_isLoad) {
_isLoad = false;
onLoad();
loadingBottomControl(state);
} else {
controller.finishLoad();
}
});
}
: null;
}
void loadingBottomControl(State state) {
Future.delayed(Duration(milliseconds: 1000), () {
state.setState(() {
if(_isMove) {
_isAutoClose = false;
} else {
_isAutoClose = true;
_isFooter = false;
}
});
});
}
}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'SmartRefresh.dart';
void main() => runApp(MyApp());
//調用EasyRefresh示例
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
// App名字
title: 'EasyRefresh',
// App主題
theme: new ThemeData(
primarySwatch: Colors.orange,
),
// 主頁
home: _Example(),
localizationsDelegates: [
GlobalEasyRefreshLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
);
}
}
class _Example extends StatefulWidget {
@override
_ExampleState createState() {
return _ExampleState();
}
}
class _ExampleState extends State<_Example> {
EasyRefreshController _controller;
// 條目總數
int _count = 1;
@override
void initState() {
super.initState();
_controller = EasyRefreshController();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("EasyRefresh"),
),
body: _easyRefreshState().buildSmartRefresh(this));
}
EasyRefresh _easyRefreshState(){
EasyRefresh refresh = EasyRefresh();
refresh = EasyRefresh.custom(
enableControlFinishRefresh: false,
enableControlFinishLoad: true,
controller: _controller,
header: ClassicalHeader(),
footer: ClassicalFooter(),
onRefresh: refresh.onSmartRefreshCallback(onRefresh,_controller),
onLoad: refresh.onSmartLoadCallback(onLoad, this,_controller),
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
width: 60.0,
height: 60.0,
child: Center(
child: Text('$index'),
),
color: index % 2 == 0
? Colors.grey[300]
: Colors.transparent,
);
},
childCount: _count,
),
),
],
);
return refresh;
}
void onRefresh() {
setState(() {
_count = 1;
});
}
void onLoad() {
setState(() {
_count += 1;
});
_controller.finishLoad(noMore: _count >= 10);
}
}
github源碼地址: