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);
}

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