flutter下拉刷新,上拉加载更多

下拉刷新

下拉刷新的默认控件RefreshIndicator,其实就是android里面的SwipeRefreshLayout一个效果;

这里有个和android不一样的概念就是future,官方给的解释:
A Future is used to represent a potential value, or error, that will be available at some time in the future. Receivers of a Future can register callbacks that handle the value or error once it is available.
理解:
Future就是event,很多Flutter内置的组件比如Http(http请求控件)的get函数、RefreshIndicator(下拉手势刷新控件)的onRefresh函数都是event。每一个被await标记的句柄也是一个event,每创建一个Future就会把这个Future扔进event queue中排队等候安检~

另外还有一个Completer,其实就是触发下拉刷新完成时调用的控制器;

下拉刷新几个要注意的点(以ListView为例)

  • 如果ListView的内容不足一屏,要设置ListView的physics属性为const AlwaysScrollableScrollPhysics()
  • onRefresh方法是接受一个Future的参数
  • 通过代码触发下拉 _refreshIndicatorKey.currentState.show();
上拉加载

flutter默认是没有上拉加载的,只能自己实现,实现的原理的话,其实就是给listview增加一个item,控制其为加载更多的item或者是已经没有更多数据的item;
这里用了一个开源库:flutter_spinkit,效果还不错;
添加依赖:

dependencies:
  flutter_spinkit: "^3.0.0"

效果如下:
在这里插入图片描述

代码如下:

class PersonalPage extends StatefulWidget {
  PersonalPage({Key key}) : super(key: key);

  @override
  _PersonalPageState createState() => new _PersonalPageState();
}

class _PersonalPageState extends State<PersonalPage> {
  List widgets = [];
  final ScrollController _scrollController = new ScrollController();

  //是否在加载
  bool isLoading = false;

  //是否有更多数据
  bool isHasNoMore = false;

  //当前页
  var currentPage = 0;

  //一页的数据条数
  final int pageSize = 20;

  //这个key用来在不是手动下拉,而是点击某个button或其它操作时,代码直接触发下拉刷新
  final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey = new GlobalKey<
      RefreshIndicatorState>();

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        _getMoreData();
      }
    });
    loadData(false);
  }

  Widget getItem(int index) {
    print("${index == widgets.length}");
    if (index == widgets.length) {
      if (isHasNoMore) {
        return _buildNoMoreData();
      } else {
        return _buildLoadMoreLoading();
      }
    } else {
      return itemBuilder(context, index);
    }
  }


  @override
  Widget build(BuildContext context) {
    return new RefreshIndicator(

      ///GlobalKey,用户外部获取RefreshIndicator的State,做显示刷新
      key: _refreshIndicatorKey,
      onRefresh: refreshHelper,
      child: new ListView.builder(

        ///保持ListView任何情况都能滚动,解决在RefreshIndicator的兼容问题。
        physics: const AlwaysScrollableScrollPhysics(),
        itemCount: widgets.length + 1,
        controller: _scrollController,
        itemBuilder: (context, index) {
          return getItem(index);
        },
      ),
    );
  }

  Future<Null> refreshHelper() {
    final Completer<Null> completer = new Completer<Null>();
    //清空数据
    widgets.clear();
    currentPage = 0;
    loadData(false, completer);
    return completer.future;
  }

  //completer可选参数
  void loadData(bool isLoadMore, [Completer completer]) async {
    String url = "http://www.wanandroid.com/article/list/${currentPage}/json?cid=60";
    if (isLoadMore) {
      setState(() => isLoading = true);
    }
    var response = await HttpUtil().get(url,
        startCallBack: () {
          print("开始");
        },
        successCallBack: (var success) {
          print("成功");
        },
        errorCallBack: () {
          print("失败");
        });
    completer?.complete();
    List data = response["data"]["datas"];
    if (data.length < pageSize) {
      isHasNoMore = true;
    } else {
      isHasNoMore = false;
    }
    if (isLoadMore) {
      setState(() {
        isLoading = false;
        widgets.addAll(data);
      });
    } else {
      setState(() {
        widgets = data;
      });
    }
  }

  Widget itemBuilder(BuildContext context, int index) {
    return new Container(
      margin: EdgeInsets.all(15.0),
      child: new Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          new Text("标题: ${widgets[index]["title"]}", textAlign: TextAlign.start,
          ),
          new Text(
            "内容: ${widgets[index]["link"]}", textAlign: TextAlign.start,),
          new Container(
            margin: EdgeInsets.only(top: 10.0),
            child: new Divider(
              height: 2.0,
            ),
          )
        ],
      ),
    );
  }


  void _getMoreData() async {
    if (!isLoading) {
      currentPage++;
      loadData(true);
    }
  }


  Widget _buildLoadMoreLoading() {
    return new Padding(
      padding: const EdgeInsets.all(8.0),
      child: new Center(
        child: new Opacity(
          opacity: isLoading ? 1.0 : 0.0,
          child: new Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              SpinKitFadingCircle(
                color: Colors.grey,
                size: 30.0,
              ),
              new Padding(padding: EdgeInsets.only(left: 10)),
              new Text("正在加载更多...")
            ],
          ),
        ),
      ),);
  }

  Widget _buildNoMoreData() {
    return new Container(
      margin: EdgeInsets.only(top: 15.0, bottom: 15.0),
      alignment: Alignment.center,
      child: new Text("没有更多数据了"),
    );
  }

  @override
  void dispose() {
    super.dispose();
    _scrollController.dispose();
  }

}



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值