flutter系列之:flutter中常用的ListView layout详解
简介
ListView是包含多个child组件的widget,在ListView中所有的child widget都是以list的形式来呈现的,你可以自定义List的方向,但是和GridView不同的是ListView中的每一个List里面都只包含一个widget。
今天我们来详细了解一下ListView的底层实现和具体的应用。
ListView详解
和GridView一样,ListView也是继承自ScrollView,表示它是一个可以滚动的View。
具体而言,ListView首先继承自BoxScrollView:
class ListView extends BoxScrollView
然后BoxScrollView又继承自ScrollView:
abstract class BoxScrollView extends ScrollView
ListView中的特有属性
首先我们来看下ListView中的特有属性,ListView和它的父类相比,多了三个属性,分别是itemExtent,prototypeItem和childrenDelegate。
其中itemExtent是一个double类型的数据,如果给定的是一个非空值,那么表示的是child在scroll方向的extent大小。这个属性主要用来控制children的extend信息,这样每个child就不需要自行来判断自己的extend。
使用itemExtent的好处在于,ListView可以统一的在滚动机制上进行优化,从而提升性能表现。
prototypeItem是一个widget,从名字就可以看出,这个一个prototype的widget,也就是说是一个原型,其他的child可以参照这个原型widget的大小进行extent的设置。
ListView中的最后一个自定义属性是childrenDelegate,这个childrenDelegate和GridView中的含义是一样的,用来生成ListView中child。
之前我们在讲解GirdView的时候有提到过,GirdView中还有一个自定义的属性叫做gridDelegate,这个gridDelegate是一个SliverGridDelegate的实例,用来控制子组件在GridView中的布局。
因为ListView的子组件的布局是已经确定的,所以就不再需要gridDelegate了,这是ListView和GridView的一大区别。
ListView作为一个继承的类,需要实现一个buildChildLayout的方法:
@override
Widget buildChildLayout(BuildContext context) {
if (itemExtent != null) {
return SliverFixedExtentList(
delegate: childrenDelegate,
itemExtent: itemExtent!,
);
} else if (prototypeItem != null) {
return SliverPrototypeExtentList(
delegate: childrenDelegate,
prototypeItem: prototypeItem!,
);
}
return SliverList(delegate: childrenDelegate);
}
这个方法的实现逻辑和我们之前讲到的三个属性是相关联的,在buildChildLayout中,如果itemExtent有值的话,因为itemExtent本身就是一个固定值,所以返回的是SliverFixedExtentList。
如果itemExtent没有设置,并且prototypeItem有值的话,返回的是一个SliverPrototypeExtentList。
最后,如果itemExtent和prototypeItem都没有设置的话,返回的是一个SliverList对象。
ListView的构造函数
和GridView一样,为了满足我们的多样性的设计需求,ListView也提供了多个构造函数。
首先我们来看下ListView的最基本的构造函数:
ListView({
Key? key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController? controller,
bool? primary,
ScrollPhysics? physics,
bool shrinkWrap = false,
EdgeInsetsGeometry? padding,
this.itemExtent,
this.prototypeItem,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
double? cacheExtent,
List<Widget> children = const <Widget>[],
int? semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
String? restorationId,
Clip clipBehavior = Clip.hardEdge,
})
这里itemExtent和prototypeItem这两个属性是外部传入的,childrenDelegate是通过其他的参数构造而来的:
childrenDelegate = SliverChildListDelegate(
children,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
addSemanticIndexes: addSemanticIndexes,
),
ListView中所有的child组件都在List Widget的children中。
这个默认的构造函数,适用于child比较少的情况,因为需要一次传入所有的child组件到list中,所以对性能的影响还是挺大的,并且传入的child是不可变的。
如果child比较多的情况下,就需要使用到其他的构造函数了,比如 ListView.builder。
ListView.builder使用的是builder模式来构建child组件,具体而言他的childrenDelegate实现如下:
childrenDelegate = SliverChildBuilderDelegate(
itemBuilder,
childCount: itemCount,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
addSemanticIndexes: addSemanticIndexes,
),
这里的childrenDelegate是一个SliverChildBuilderDelegate,通过传入itemBuilder和总的itemCount就可以实现动态创建child的功能。
在ListView的实际使用过程中,为了页面好看或者更有区分度,我们一般会在list的item中添加一些分隔符separator,为了自动化实现这个功能,ListView提供了一个ListView.separated的构造函数,用来提供list item中间的分隔符。
ListView.separated需要传入两个IndexedWidgetBuilder,分别是itemBuilder和separatorBuilder。
下面是childrenDelegate的具体实现:
childrenDelegate = SliverChildBuilderDelegate(
(BuildContext context, int index) {
final int itemIndex = index ~/ 2;
final Widget widget;
if (index.isEven) {
widget = itemBuilder(context, itemIndex);
} else {
widget = separatorBuilder(context, itemIndex);
assert(() {
if (widget == null) {
throw FlutterError('separatorBuilder cannot return null.');
}
return true;
}());
}
return widget;
},
childCount: _computeActualChildCount(itemCount),
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
addSemanticIndexes: addSemanticIndexes,
semanticIndexCallback: (Widget _, int index) {
return index.isEven ? index ~/ 2 : null;
},
),
可以看到,如果index是even的话就会使用itemBuilder生成一个widget,如果index是odd的话,就会使用separatorBuilder来生成一个separator的widget。
最后,ListView还有一个更加开放的构造函数ListView.custom,custom和其他构造函数不同的地方在于他可以自定义childrenDelegate,从而提供了更多的扩展空间。
ListView的使用
有了上面的构造函数,我们可以很方便的根据自己的需要来使用ListView,下面是一个简单的使用图片做child的例子:
class ListViewApp extends StatelessWidget{
const ListViewApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 5,
itemBuilder: (BuildContext context, int index) {
return Container(
constraints: const BoxConstraints(maxWidth:100,maxHeight: 100),
child: Image.asset('images/head.jpg')
);
},
);
}
}
上面的例子中,我们使用的是ListView.builder构造函数,返回的Widget中,中的widget个数是5,每个item是由itemBuilder来生成的。
这里我们把Image封装在一个Container中,并且为Container设置了一个constraints来控制图片的大小。
最终生成的界面如下:
上面的例子中,item之间是没有分隔符的,我们可以讲上面的例子进行稍微的修改一下,使用ListView.separated来构造ListView,如下所示:
class ListViewSeparatedApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: 10,
separatorBuilder: (BuildContext context, int index) => const Divider(),
itemBuilder: (BuildContext context, int index) {
return Container(
constraints: const BoxConstraints(maxWidth:50,maxHeight: 50),
child: Image.asset('images/head.jpg')
);
},
);
}
}
这里我们需要传入separatorBuilder来作为分隔符,为了简单起见,我们直接使用了Divider这个widget。
最后生成的界面如下:
总结
以上就是ListView的介绍和基本的使用。
本文的例子:https://github.com/ddean2009/learn-flutter.git
flutter系列之:flutter中常用的ListView layout详解的更多相关文章
- flutter系列之:flutter中常用的Stack layout详解
[toc] 简介 对于现代APP的应用来说,为了更加美观,通常会需要用到不同图像的堆叠效果,比如在一个APP用户背景头像上面添加一个按钮,表示可以修改用户信息等. 要实现这样的效果,我们需要在一个Im ...
- flutter系列之:flutter中常用的GridView layout详解
目录 简介 GridView详解 GridView的构造函数 GridView的使用 总结 简介 GridView是一个网格化的布局,如果在填充的过程中子组件超出了展示的范围的时候,那么GridVie ...
- flutter系列之:flutter中常用的container layout详解
目录 简介 Container的使用 旋转Container Container中的BoxConstraints 总结 简介 在上一篇文章中,我们列举了flutter中的所有layout类,并且详细介 ...
- Android总结篇系列:Activity中几个主要函数详解
Activity作为Android系统中四大基本组件之一,包含大量的与其他的各大组件.intent.widget以及系统各项服务等之间的交互的函数.在此,本文主要选取实际项目开发中常用的,但完全理解又 ...
- java日志框架系列(7):logback框架Layout详解
1.Layout layout从字面意思来看就是排版.布局咯. 1.Layout简介 功能:负责把事件转换成字符串.Layout接口的格式化方法doLayout()负责将代表任何类型的事件的转换成一个 ...
- flutter系列之:构建Widget的上下文环境BuildContext详解
目录 简介 BuildContext的本质 BuildContext和InheritedWidget BuildContext的层级关系 总结 简介 我们知道Flutter中有两种Widget,分别是 ...
- Windows学习总结(10)——Windows系统中常用的CMD命令详解
1.ping命令 ping是电脑网络故障诊断中的常用的命令,它的作用是用来检查网络是否通畅或者网络连接速度.我们来看一下PING命令的具体表述. 日常的诊断过程中我们最常用到的就是诊断连接是否通畅. ...
- [ES6系列-03]ES6中关于参数相关特性详解(参数默认值与参数解构赋值与剩余参数)
[原创] 码路工人 大家好,这里是码路工人有力量,我是码路工人,你们是力量. 今天总结一下 ES6 中跟参数相关的内容. 欢迎补充斧正.留言交流. 让我们互相学习一起进步. 1. ES6 参数默认值( ...
- Oracle中常用的to_char用法详解
Oracle函数to_char转化数字型指定小数点位数的用法 to_char,函数功能,就是将数值型或者日期型转化为字符型. 比如最简单的应用: -- 1.0123=>1.0123 SELECT ...
随机推荐
- 螣龙安科反入侵:EDR的缺点
EDR解决方案提供了比传统终结点安全解决方案更高的功能,并且可以增加人员数量,但是这些功能都有不少的缺点. EDR功能付出巨大代价 在过去四年中,虽然产品成本平均每年下降约35%,但即使到今天,产品的 ...
- Hash 哈希表和算法思路详解
概述 哈希表是一种可以满足快速查找数据结构,时间复杂度接近O(1). 哈希函数是无限集到有限集的映射. 处理数据量大,查找效率要求高时推荐使用hash容器. 问题: 什么情况下考虑使用哈希容器? 常用 ...
- 适用于MES、WMS、ERP等管理系统的实体下拉框设计
场景 该设计多适用于MES,ERP,WMS 等管理类型的项目. 在做管理类型项目的时候,前端经常会使用到下拉框,比如:设备,工厂等等.下拉组件中一般只需要他们的ID,Name属性,而这些数据都创建于其 ...
- 1_day01_操作系统安装
操作系统安装 内容介绍 1.制作U盘启动器 2.备份驱动 3.安装操作系统 4.驱动更新 5.依赖库检测 6.系统漏洞修复 7.系统布局优化 一.制作U盘启动器 1.1 下载老毛桃 下载老毛桃pe工具 ...
- CF1701A Grass Field 题解
根据题意,给定一个 \(2\times2\) 的仅包含 \(0\) 和 \(1\) 的二维数组.定义一个操作,每次可以选择一行和一列将其变成 \(0\),求最小操作次数. 思路:根据枚举可得共有 \( ...
- display: table-cell里面文字打点的方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- JS中的数据类型及转换
js的六大类型 js中有六种数据类型,Boolean: 布尔类型 Number:数字(整数int,浮点数float ) String:字符串 Object:对象 (包含Array数组 ) 特殊数据类型 ...
- 利用Docker挂载Nginx-rtmp(服务器直播流分发)+FFmpeg(推流)+Vue.js结合Video.js(播放器流播放)来实现实时网络直播
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_75 众所周知,在视频直播领域,有不同的商家提供各种的商业解决方案,其中比较靠谱的服务商有阿里云直播,腾讯云直播,以及又拍云和网易云 ...
- 【原创】Python 网易易盾滑块验证
本文仅供学习交流使用,如侵立删! 记一次 网易易盾滑块验证分析并通过 操作环境 win10 . mac Python3.9 selenium.PIL.numpy.scipy.matplotlib 分析 ...
- Win10使用fvm管理多个Flutter版本
Win10使用fvm管理多个Flutter版本 参考:https://blog.csdn.net/PyMuma/article/details/115298645 1.升级Flutter 由于现在的f ...