Flutter——Listview的下拉刷新和上拉加载更多

声明:本篇博客是上一篇博客的扩展,在原有的基础上实现下拉刷新和上拉加载更多功能。
地址:https://blog.csdn.net/weixin_43851639/article/details/100707373

下拉刷新

Flutter 框架中 RefreshIndicator 组件提供了下拉刷新的功能。使用该组件,需要实现一个刷新函数。
组件使用如下:

body: RefreshIndicator(
  onRefresh: _onRefresh,
  child: ListView.separated(
    controller: _scrollController,
    //下拉加载更多需要显示一个加载组件,需要占用一个listtile位置,所以长度需要+1
    itemCount: _list.length + 1,
    itemBuilder: (BuildContext context, int index) => _buildRow(index),
    //子项的分割线
    separatorBuilder: (BuildContext context,int index) => Divider(),
  ),
),

刷新函数 _onRefresh() 代码如下,这里为了方便测试,直接删除列表的第一项元素:

//刷新数据
Future<Null> _onRefresh() async {
   //刷新时间为3s
   await Future.delayed(Duration(seconds: 3),(){
     setState(() {
       //为了测试,刷新后直接将_list第一项数据删除,实际中则是网络请求数据
       _list.removeAt(0);
     });
   });
 }

这样下拉刷新的功能就简单实现了。
效果如下:
在这里插入图片描述

上拉加载更多

上拉加载更多可能稍微复杂一点,不仅要考虑加载数据的问题,还要显示加载更多的提示,提高用户体验。
上拉加载更多是通过 ScrollController 来实现的。

定义如下:

//listview的控制器
ScrollController _scrollController = ScrollController();

并且需要为其添加监听:

_scrollController.addListener(() {
 if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
    print("上拉加载更多");
    _getMore();
  }
});

上拉加载需要一个提供数据的函数 _getMore() ,为了便于测试,这里随机添加原有数据,代码如下:

//上拉加载更多
Future<Null> _getMore() async {
   Future.delayed(Duration(seconds: 1),() {
     //为了测试,随机添加原有_list中的数据
     setState(() {
       _list.add(_list[1]);
       for (int i=0; i<4; i++) {
         int num = Random().nextInt(_list.length);
         _list.add(_list[num]);
       }
     });
   });
 }

当数据为组后一条时,需要显示一个加载更多的组件:

//上拉加载更多组件
Widget _getMoreWidget() {
   return Center(
     child: Padding(
       padding: EdgeInsets.all(10.0),
       child: Text(
         '加载中...',
         style: TextStyle(fontSize: 16.0),
       ),
     ),
   );
 }

判断何时显示加载更多组件,何时显示原有数据项:

在这里插//构造listtile
Widget _buildRow(int index) {
  if (index < _list.length) {
    return Padding(
      padding: EdgeInsets.all(20.0),
      child: ListTile(
        title: Text(_list[index].userName),
        leading: CircleAvatar(
          backgroundImage: NetworkImage("http://00.000.000.000:8080/images/" + _list[index].avatarUrl),
        ),
      ),
    );
  }
  //此处显示加载更多组件
  return _getMoreWidget();
}

需要注意的地方,ListView 中的 itemCount 需要在 _list 长度的基础上加1

//下拉加载更多需要显示一个加载组件,需要占用一个listtile位置,长度需要+1
itemCount: _list.length + 1,

上拉加载更多效果如图:
在这里插入图片描述

完整代码如下:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:math';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.lightBlue,
      ),
      home: ListviewHttp(),
    );
  }
}

class ListviewHttp extends StatefulWidget {
  @override
  ListviewHttpState createState() {
    return new ListviewHttpState();
  }
}

class ListviewHttpState extends State<ListviewHttp> {
  List<ListData> _list = [];
  //listview的控制器
  ScrollController _scrollController = ScrollController();

  //异步加载数据
  _loadData() async {
    String url = "http://00.000.000.000:8080/yiqijiu/GetHelpInfo";
    http.Response response = await http.get(url);
    setState(() {
      final data = jsonDecode(response.body);
      for (var _data in data) {
        _list.add(ListData(_data["patientName"],_data["patientPortrait"]));
      }
    });
  }

  //构造listtile
  Widget _buildRow(int index) {
    if (index < _list.length) {
      return Padding(
        padding: EdgeInsets.all(20.0),
        child: ListTile(
          title: Text(_list[index].userName),
          leading: CircleAvatar(
            backgroundImage: NetworkImage("http://00.000.000.000:8080/images/" + _list[index].avatarUrl),
          ),
        ),
      );
    }
    return _getMoreWidget();
  }

  //上拉加载更多组件
  Widget _getMoreWidget() {
    return Center(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Text(
          '加载中...',
          style: TextStyle(fontSize: 16.0),
        ),
      ),
    );
  }

  //初始化状态
  @override
  void initState() {
    super.initState();
    _loadData();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
        print("上拉加载更多");
        _getMore();
      }
    });
  }

  //刷新数据
  Future<Null> _onRefresh() async {
    //刷新时间为3s
    await Future.delayed(Duration(seconds: 3),(){
      setState(() {
        //为了测试,刷新后直接将_list第一项数据删除,实际中则是网络请求数据
        _list.removeAt(0);
      });
    });
  }

  //上拉加载更多
  Future<Null> _getMore() async {
    Future.delayed(Duration(seconds: 1),() {
      //为了测试,随机添加7条原有_list中的数据
      setState(() {
        _list.add(_list[1]);
        for (int i=0; i<4; i++) {
          int num = Random().nextInt(_list.length);
          _list.add(_list[num]);
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Listview Http Test"),
      ),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.separated(
          controller: _scrollController,
          //下拉加载更多需要显示一个加载组件,需要占用一个listtile位置,所以长度需要+1
          itemCount: _list.length + 1,
          itemBuilder: (BuildContext context, int index) => _buildRow(index),
          //子项的分割线
          separatorBuilder: (BuildContext context,int index) => Divider(),
        ),
      ),
    );
  }
}

//数据类,将json数据转换为对象
class ListData {
  final String userName;
  final String avatarUrl;
  ListData(this.userName, this.avatarUrl);
}

发布了38 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43851639/article/details/100709617