前言

它可以沿一个方向线性排布所有子组件,并且它也可以支持基于Sliver的延迟构建模型。

接口描述

ListView({
Key key,
// 可滚动widget公共参数
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
EdgeInsetsGeometry padding,
// ListView各个构造函数的共同参数
// 该参数如果不为null,则会强制children的“长度”为itemExtent的值;这里的“长度”是指滚动方向上子组件的长度,也就是说如果滚动方向是垂直方向,则itemExtent代表子组件的高度;如果滚动方向为水平方向,则itemExtent就代表子组件的宽度。在ListView中,指定itemExtent比让子组件自己决定自身长度会更高效,这是因为指定itemExtent后,滚动系统可以提前知道列表的长度,而无需每次构建子组件时都去再计算一下,尤其是在滚动位置频繁变化时(滚动系统需要频繁去计算列表高度)。
this.itemExtent,
// 该属性表示是否根据子组件的总长度来设置ListView的长度,默认值为false 。默认情况下,ListView的会在滚动方向尽可能多的占用空间。当ListView在一个无边界(滚动方向上)的容器中时,shrinkWrap必须为true。
bool shrinkWrap = false,
// 该属性表示是否将列表项(子组件)包裹在AutomaticKeepAlive 组件中;典型地,在一个懒加载列表中,如果将列表项包裹在AutomaticKeepAlive中,在该列表项滑出视口时它也不会被GC(垃圾回收),它会使用KeepAliveNotification来保存其状态。如果列表项自己维护其KeepAlive状态,那么此参数必须置为false。
bool addAutomaticKeepAlives = true,
// 该属性表示是否将列表项(子组件)包裹在RepaintBoundary组件中。当可滚动组件滚动时,将列表项包裹在RepaintBoundary中可以避免列表项重绘,但是当列表项重绘的开销非常小(如一个颜色块,或者一个较短的文本)时,不添加RepaintBoundary反而会更高效。和addAutomaticKeepAlive一样,如果列表项自己维护其KeepAlive状态,那么此参数必须置为false。
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double cacheExtent,
// 子widget列表
List<Widget> children = const <Widget>[],
int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
})

代码示例

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart'; // ListView 默认构造函数
/* 默认构造函数有一个children参数,它接受一个Widget列表(List)。这种方式适合只有少量的子组件的情况,因为这种方式需要将所有children都提前创建好(这需要做大量工作),而不是等到子widget真正显示的时候再创建,也就是说通过默认构造函数构建的ListView没有应用基于Sliver的懒加载模型。实际上通过此方式创建的ListView和使用SingleChildScrollView+Column的方式没有本质的区别。*/
class ListViewTest1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ListView 默认构造函数'),
),
body: ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(20.0),
children: <Widget>[
const Text('I\'m haha'),
const Text('biubiubiu`'),
const Text('qiuqiuqiu`'),
const Text('dindindin`'),
const Text('I\'m haha'),
const Text('biubiubiu`'),
const Text('qiuqiuqiu`'),
const Text('dindindin`'),
const Text('I\'m haha'),
const Text('biubiubiu`'),
const Text('qiuqiuqiu`'),
const Text('dindindin`'),
],
),
);
}
} // ListView.builder
/* ListView.builder适合列表项比较多(或者无限)的情况,因为只有当子组件真正显示的时候才会被创建,也就说通过该构造函数创建的ListView是支持基于Sliver的懒加载模型的。*/
class ListViewTest2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ListView 默认构造函数'),
),
body: ListView.builder(
// 列表项的数量,如果为null,则为无限列表
itemCount: 100,
itemExtent: 50.0,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("$index"),);
}
)
);
}
} // ListView.separated
/*ListView.separated可以在生成的列表项之间添加一个分割组件,它比ListView.builder多了一个separatorBuilder参数,该参数是一个分割组件生成器。 */
class ListViewTest3 extends StatelessWidget { Widget build(BuildContext context) {
// 下划线widget预定义以供复用
Widget divider1 = Divider(color: Colors.blue,);
Widget divider2 = Divider(color: Colors.green,);
return Scaffold(
appBar: AppBar(
title: Text('ListView.separated'),
),
body: ListView.separated(
// 列表项构造器
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text('$index'),);
},
// 分割器构造器
separatorBuilder: (BuildContext context, int index) {
return index%2==0?divider1:divider2;
},
itemCount: 100
),
);
}
} // 实例:无限加载列表
class InfiniteListView extends StatefulWidget {
@override
_InfiniteListViewState createState() => _InfiniteListViewState();
} class _InfiniteListViewState extends State<InfiniteListView> {
// 表尾标记
static const loadingTag = "##loadding##";
var _words = <String>[loadingTag]; @override
void initState() {
super.initState();
_retrieveData();
} @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ListView.separated'),
),
body: ListView.separated(
itemBuilder: (context, index) {
// 如果到了表尾
if (_words[index] == loadingTag) {
// 不足100条,继续获取数据
if (_words.length - 1 < 100) {
// 获取数据
_retrieveData();
// 加载时显示loading
return Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
child: CircularProgressIndicator(strokeWidth: 2.0,),
),
);
} else {
// 已经加载了100条数据,不再获取数据
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16.0),
child: Text('已经到我的底线了ฅʕ•̫͡•ʔฅ'),
);
}
}
// 显示单词列表项
return ListTile(title: Text(_words[index]),);
},
separatorBuilder: (context, index) => Divider(height: .0,),
itemCount: _words.length,
),
);
} // 模拟从数据源异步获取数据
void _retrieveData() {
Future.delayed(Duration(seconds: 2)).then((e) {
_words.insertAll(
_words.length - 1,
// 每次生成20个单词
generateWordPairs().take(20).map((e) => e.asPascalCase).toList()
);
setState(() {
// 重新构建列表
});
});
}
}

总结

不同的构造函数对应了不同的列表项生成模型,如果需要自定义列表项生成模型,可以通过ListView.custom来自定义,它需要实现一个SliverChildDelegate用来给ListView生成列表项组件。

【Flutter】可滚动组件之ListView的更多相关文章

  1. 【Flutter学习】可滚动组件之ScrollView

    一,概述 ScrollView 是一个带有滚动的视图组件. 二,组成部分 ScrollView 由三部分组成: Scrollable - 它监听各种用户手势并实现滚动的交互设计.可滚动Widget都直 ...

  2. 【Flutter】可滚动组件之滚动控制和监听

    前言 可以用ScrollController来控制可滚动组件的滚动位置. 接口描述 ScrollController({ // 初始滚动位置 double initialScrollOffset = ...

  3. 【Flutter】可滚动组件之CustomScrollView

    前言 CustomScrollView是可以使用Sliver来自定义滚动模型(效果)的组件.它可以包含多种滚动模型,举个例子,假设有一个页面,顶部需要一个GridView,底部需要一个ListView ...

  4. 【Flutter】可滚动组件之SingleChildScrollView

    前言 SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件. 接口描述 const SingleChildScrollView({ Key ke ...

  5. 【Flutter】可滚动组件简介

    前言 当组件内容超过当前显示视口(ViewPort)时,如果没有特殊处理,Flutter则会提示Overflow错误.为此,Flutter提供了多种可滚动组件(Scrollable Widget)用于 ...

  6. 第29讲 UI组件之 ListView与 BaseAdapter,SimpleAdapter

    第29讲 UI组件之 ListView与 BaseAdapter,SimpleAdapter 1.BaseAdapter BaseAdapter是Android应用程序中经常用到的基础数据适配器,它的 ...

  7. 第28讲 UI组件之 ListView和ArrayAdapter

    第28讲 UI组件之 ListView和ArrayAdapter 1. Adapter 适配器 Adapter是连接后端数据和前端显示的适配器接口,是数据和UI(View)之间一个重要的纽带.在常见的 ...

  8. Android常见UI组件之ListView(二)——定制ListView

    Android常见UI组件之ListView(二)--定制ListView 这一篇接上篇.展示ListView中选择多个项及实现筛选功能~ 1.在位于res/values目录下的strings.xml ...

  9. Flutter 常用组件

    无状态组件(StatelessWidget)是不可变的,这意味着它的属性不能改变,所有的值都是最终的. 有状态组件(StatefulWidget)持有的状态可能在Widget生命周期中发生变化.实现一 ...

随机推荐

  1. APIO2012 苦无 Kunai

    这题网上貌似还没有完整的题解呢,我来口胡一下~ Description \(W \times H\) 的二维坐标系,\(W, H \le 10^9\) 给 \(n (n \le 10^5)\) 个点 ...

  2. 通过Spring profile方式实现多环境部署

    1 多环境部署 在实际软件开发和部署过程中,我们的软件往往需要在不同的运行环境中运行.例如,各个环境数据库地址不同,需要单独配置.spring高级装备中提供profile,来支持多环境部署. 1.1 ...

  3. 手把手教你:将 ClickHouse 集群迁至云上

    前言 随着云上 ClickHouse 服务完善,越来越多的用户将自建 ClickHouse 服务迁移至云上.对于不同数据规模,我们选择不同的方案: 对于数据量比较小的表,通常小于10GB 情况下,可以 ...

  4. 【python爬虫】一个简单的爬取百家号文章的小爬虫

    需求 用"老龄智能"在百度百家号中搜索文章,爬取文章内容和相关信息. 观察网页 红色框框的地方可以选择资讯来源,我这里选择的是百家号,因为百家号聚合了来自多个平台的新闻报道.首先看 ...

  5. 前方高能!看Python程序员是表白的

    一.️爱心墙️ 通过爬虫搜集到粉丝的头像,然后利用PIL库拼接出爱心墙的形状: 二.代码分析 1.头像爬取 在个人中心点击我的粉丝便可以看到自己的粉丝,通过抓包可知对应的接口为: url = 'htt ...

  6. java基础:进制详细介绍,进制快速转换,二维数组详解,循环嵌套应用,杨辉三角实现正倒直角正倒等腰三角,附练习案列

    1.Debug模式 1.1 什么是Debug模式 是供程序员使用的程序调试工具,它可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序. 1.2 Debug介绍与操作流程 如何加断点 选择 ...

  7. NET Core 使用EF Core的Code First迁移和DBFirst

    DBFirst (1)Microsoft.EntityFrameworkCore (2)Microsoft.EntityFrameworkCore.Design (3)Microsoft.Entity ...

  8. Autofac官方文档翻译--一、注册组件--1注册概念

    官方文档:http://docs.autofac.org/en/latest/register/registration.html 一.注册概念 使用Autofac 注册组件,通过创建一个Contai ...

  9. 从零开始部署发布Java项目到服务器的Docker中

    本以为很简单,由于没用过docker和java,本文将会阐述一路遇到的拦路虎. 首先,写好Java项目,本地跑通. 可能会遇到的问题: 1.jar包正常运行,war包404: 如何打包很多教程都有介绍 ...

  10. Tensorflow2.0-mnist手写数字识别示例

    Tensorflow2.0-mnist手写数字识别示例   读书不觉春已深,一寸光阴一寸金. 简介:通过CNN 卷积神经网络训练后识别出手写图片,测试图片mnist数据集中的0.1.2.4.     ...