flutter_easyrefresh 加载多次问题修复

flutter_easyrefresh 是一个下拉刷新上拉加载的插件,具体我就不介绍了,这里主要是解决flutter_easyrefresh的bug,主要我在用此插件的时候遇到如下两个问题:

①.上拉加载最后的footer不消失

②.加载少量数据出现多次加载现象解决方案

如下是问题及解决过程,如果想直接看最终解决方案请拉到最后面有最终版本

 

第一个问题现象如下,就是加载过程中在数据不能占满整个界面的时候footer是不会自动消失的

flutter_easyrefresh 加载多次问题修复_第1张图片

解决方案:加载完成延时一秒将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: [
              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: [
              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: [
              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: [
              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: [
        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源码地址:

https://github.com/gonglipeng/SmartRefresh.git

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐