flutter_easyrefresh 加載多次問題修復

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源碼地址:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章