Flutter 使用ListView的separated构造一个带下拉加载的列表

先看大致效果,因为转成GIF的原因有些失真

在这里插入图片描述

一、前言

首先,我们会用到几个Widget:

  1. ListView:item列表
  2. ListTitle:item标题
  3. CircularProgressIndicator:进度圈
  4. Divider:分割线

然后会用到一个自动生成单词的库:english_words

二、开始

一、引入单词库

pubspec.yaml 文件里依赖
在这里插入图片描述

二、构建page

1. 引入包

import 'package:english_words/english_words.dart';

2. 创建page

因为涉及到状态改变,所以继承 StatefulWidget

class FunctionPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _FunctionPageState();
}
3. 为page创建state
class _FunctionPageState extends State<FunctionPage>{
  @override
  Widget build(BuildContext context) {
    return null;
}
至此,page就构建完成了。

三、用separated构建ListView

首先思考我们要的效果是什么?跟Android里一样的套路!

  1. 总共加载80条内个item
  2. 一次加载15条数据
  3. 15条加载完成是进度圈
  4. 80条加载完后显示Foot:没有更多数据了
1. 构建ListView
  // 定义一个存放单词的数组
  List<String> _list = <String>[''];
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.separated(
      	  // 1、首先,需要传入一个item
          itemBuilder: (BuildContext context, int index) { },
          // 2、其次,传入分隔符
          separatorBuilder: (BuildContext context, int index) { },
          // 3、最后,是定义的item总个数
          itemCount: null),
    );
  }
2. 构建分隔符,定义item总数

从最简单的入手,我们先搞定分隔符和itemCount

itemCount我们给数组的长度

itemCount: _list.length

分隔符随便给个高度,颜色值flutter统一封装在Colors类里,使用很方便,而且支持渐变扩展。如果要设置样式直接设置Style即可。

separatorBuilder: 
	(BuildContext context, int index) {
      return Divider(
         height: 1,
         color: Colors.cyan,
    	);
    }
3. 接下来就是item了

itemBuilder会在每一个条目构建时回调,跟recyclerview的onBindHolder一个道理。

如果要直接使用list,如下:

itemBuilder: (BuildContext context, int index) {
    // 返回item数据
    return ListTile(title: Text(_list[index]),
  );
}

我们有几个目标:

  1. index等于list最后一个item时显示Loading对话框;反之显示item。
  2. count小于80时返回item;
  3. count大于80时返回Foot view;

合并一下,于是我们得到以下逻辑:

itemBuilder: (BuildContext context, int index) {
	if (index == _list.length - 1) {
		if(_list.length - 1 < 80){
			//  index等于list最后一个item,且count小于80时,返回Loading对话框
			return 对话框;// 伪代码
		}else{
			// count大于80时,返回Foot view
			return '没有更多数据了。。。‘;// 伪代码
		}
 	}

    // 返回item数据
    return ListTile(title: Text(_list[index]),
  );
}
4. 逻辑构建完成,就该show us the code了
itemBuilder: (BuildContext context, int index) {
	if (index == _list.length - 1) {
		// 当item count小于80个时返回一个
	  if (_list.length - 1 < 80) {
   	 	 _loadWords(); // 在显示loading时,加载数据

	 	 // 最后一个显示加载对话框
	 	 return Container(
    		padding: EdgeInsets.all(15),// Padding值封装在EdgeInsets类里
    		alignment: Alignment.center,// 内部居中
    		child: CircularProgressIndicator(),// 使用圆形进度圈
	  	 );
   	  } else {
   	  	 return Container(
    		padding: EdgeInsets.all(15),
  			alignment: Alignment.center,
 			child: Text('没有更多数据了...',style: TextStyle(color: Colors.green),),
   	  	 );
 	  }
 	}

    // 返回item数据
    return ListTile(title: Text(_list[index]),
  );
}

四、构建加载数据的逻辑

直接贴代码吧

/// 生成单词从列表最后一行插入
  void _loadWords() {
  	// Future是个好东西
    Future.delayed(Duration(milliseconds: 700)).then((e) {
      _list.insertAll(_list.length - 1,
          // 一次取出15个单词,转成String再转成list添加到集合
          generateWordPairs().take(15).map((e) => e.asPascalCase).toList());

      setState(() {});// TODO 不要调用setState刷新状态
    });
  }

在page初始化时调用加载第一次数据

@override
  void initState(){
    super.initState();
    _loadWords();// 加载数据
  }

五、结束了,贴上全部代码吧

有错误的地方欢迎指出,向Flutter进军吧!!!

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

class FunctionPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _FunctionPageState();
}

class _FunctionPageState extends State<FunctionPage>{
  List<String> _list = <String>[''];

  /// 生成单词从列表最后一行插入
  void _loadWords() {
    Future.delayed(Duration(milliseconds: 700)).then((e) {
      _list.insertAll(_list.length - 1,
          generateWordPairs().take(15).map((e) => e.asPascalCase).toList());

      setState(() {});// TODO 不要忘记这里更改状态
    });
  }

  @override
  void initState(){
    super.initState();
    _loadWords();// 加载数据
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.separated(
          itemBuilder: (BuildContext context, int index) {

            if (index == _list.length - 1) {
              if (_list.length - 1 < 80) {
                _loadWords(); // 在显示loading时,加载数据

                // 最后一个显示加载对话框
                return Container(
                  padding: EdgeInsets.all(15),
                  alignment: Alignment.center,
                  child: CircularProgressIndicator(),
                );
              } else {
                return Container(
                  padding: EdgeInsets.all(15),
                  alignment: Alignment.center,
                  child: Text('没有更多数据了...',style: TextStyle(color: Colors.green),),
                );
              }
            }

            // 返回item数据
            return ListTile(
              title: Text(_list[index]),
            );
          },
          separatorBuilder: (BuildContext context, int index) {
            return Divider(
              height: 1,
              color: Colors.cyan,
            );
          },
          itemCount: _list.length),
    );
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柯基爱蹦跶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值