当前位置:网站首页>Flutter 基础组件之 ListView
Flutter 基础组件之 ListView
2022-06-29 09:16:00 【禽兽先生不禽兽】
跟 Android 中的 ListView 差不多,就是一个可滚动的列表,这种组件在开发中是很常用的。
1 构造方法
ListView({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, double itemExtent, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, double cacheExtent, List<Widget> children: const [], int semanticChildCount })
根据显式的 Widget 集合来创建一个 ListView。
ListView.builder({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, double itemExtent, @required IndexedWidgetBuilder itemBuilder, int itemCount, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, double cacheExtent, int semanticChildCount })
根据需要来自定义创建 ListView,该构造方法必传的一个参数为 itemBuilder,它是一个 IndexedWidgetBuilder ,它的构造方法中会返回 index,可以根据这个 index 来让 ListView 的子 Item 有不同的展示。
ListView.custom({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, double itemExtent, @required SliverChildDelegate childrenDelegate, double cacheExtent, int semanticChildCount })
创建一个自定义子模型的 ListView。
ListView.separated({Key key, Axis scrollDirection: Axis.vertical, bool reverse: false, ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, @required IndexedWidgetBuilder itemBuilder, @required IndexedWidgetBuilder separatorBuilder, @required int itemCount, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, double cacheExtent })
创建一个带分隔的 ListView,这个分隔可以帮助我们实现分隔线的效果,它除了要传入一个 itemBuilder 之外,还要传入一个 separatorBuilder,这个就是分隔线。
2 常用属性
childrenDelegate:自定义子模型时用到。
itemExtent:Item 的范围,scrollDirection 为 Axis.vertical 时限制高度,scrollDirection 为 Axis.horizontal 限制宽度。
cacheExtent:预加载的区域。
controller:滑动监听,值为一个 ScrollController 对象,这个属性应该可以用来做下拉刷新和上垃加载,后面详细研究。
padding:整个 ListView 的内间距。
physics:设置 ListView 如何响应用户的滑动行为,值为一个 ScrollPhysics 对象,它的实现类常用的有:
AlwaysScrollableScrollPhysics:总是可以滑动。
NeverScrollableScrollPhysics:禁止滚动。
BouncingScrollPhysics:内容超过一屏,上拉有回弹效果。
ClampingScrollPhysics:包裹内容,不会有回弹,感觉跟 AlwaysScrollableScrollPhysics 差不多。
primary:是否是与 PrimaryScrollController 关联的主滚动视图,若为 true 则 controller 必须为空。
reverse:Item 的顺序是否反转,若为 true 则反转。
scrollDirection:ListView 的方向,为 Axis.vertical 表示纵向,为 Axis.horizontal 表示横向。
shrinkWrap:不太明白。
itemCount:子 Item 数量,只有使用 new ListView.builder() 和 new ListView.separated() 构造方法的时候才能指定,其中 new ListView.separated() 是必须指定。
下面是一个设置了上述属性的 Demo:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
//是否显示 debug 标签
debugShowCheckedModeBanner: false,
title: "ListView",
home: Scaffold(
appBar: new AppBar(
title: new Text("ListView"),
),
body: new Container(
child: new MyListView1(),
),
),
);
}
}
class MyListView1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
List<Widget> widgetList = new List();
for (int i = 0; i < 100; i++) {
widgetList.add(new MyText("Item " + i.toString()));
}
ScrollController scrollController = new ScrollController();
scrollController.addListener(() {
print("scrollController--->" + scrollController.offset.toString());
});
return new ListView(
//Item 的范围,scrollDirection 为 Axis.vertical 时限制高度,scrollDirection 为 Axis.horizontal 限制宽度
itemExtent: 30,
// shrinkWrap: true,
//预加载的区域
// cacheExtent: 0,
//滑动监听,值为一个 ScrollController 对象
controller: scrollController,
// //内边距
padding: EdgeInsets.all(10),
//设置 ListView 如何响应用户的滑动行为,值为一个 ScrollPhysics 对象,它的实现类常用的有:
//AlwaysScrollableScrollPhysics:总是可以滑动
//NeverScrollableScrollPhysics:禁止滚动
//BouncingScrollPhysics:内容超过一屏,上拉有回弹效果
//ClampingScrollPhysics:包裹内容,不会有回弹,感觉跟 AlwaysScrollableScrollPhysics 差不多
physics: new BouncingScrollPhysics(),
//是否是与 PrimaryScrollController 关联的主滚动视图,若为 true 则 controller 必须为空
// primary: true,
//Item 的顺序是否反转,若为 true 则反转
reverse: true,
//ListView 的方向,为 Axis.vertical 表示纵向,为 Axis.horizontal 表示横向
// scrollDirection: Axis.vertical,
children: widgetList,
);
}
}
运行效果如下:

上面是用第一种构造方法创建的 ListView,接下来使用 Builder 来创建一下 ListView,它与普通的构造方法不同的是,普通构造方法传入的是已经创建好的子组件集合,而 Builder 是先指定子组件的个数,然后在 itemBuilder 中可以知道子组件所属的 position,根据这个 position 可以创建不同的子组件:
class MyListView2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
if (index.isOdd) {
return new Container(
padding: new EdgeInsets.all(15.0),
child: new Text(
"builder 奇数 Item " + index.toString(),
style:
new TextStyle(fontSize: 20.0, color: new Color(0xFFFF0000)),
),
);
} else {
return new Container(
padding: new EdgeInsets.all(15.0),
child: new Text(
"builder 偶数 Item " + index.toString(),
style:
new TextStyle(fontSize: 20.0, color: new Color(0xFF0000FF)),
),
);
}
},
);
}
}
运行效果如下:

其实使用 Builder 来构造 ListView 的话,也可以实现分隔线的效果,只需要根据 position 一个返回子组件,下一个返回分隔线组件即可:
class MyListView2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView.builder(
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
if (index.isOdd) {
return Container(
padding: EdgeInsets.all(15.0),
child: Text(
"builder 奇数 Item " + index.toString(),
style:
new TextStyle(fontSize: 20.0, color: new Color(0xFFFF0000)),
),
);
} else {
return Divider(color: Color(0xFF000000),);
}
},
);
}
}
这样写出来会是这种效果:

虽然实现了分隔线效果,但是想必从 Item 上的文字就能看出问题,分隔线是占了 Item 的位置的,所以如果要用这种方式来实现分隔线的话,子组件的长度会增大一倍,因为一半都给了分隔线,所以实现分隔线的话一般是使用 ListView.separated() 构造方法:
class MyListView3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
List<Widget> widgetList = new List();
for (int i = 0; i < 100; i++) {
widgetList.add(new MyText("Item " + i.toString()));
}
return new ListView.separated(
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
print("itemBuilder--->" + index.toString());
return new Container(
padding: new EdgeInsets.all(15.0),
child: new Text(
"separated Item " + index.toString(),
style: new TextStyle(fontSize: 20.0, color: new Color(0xFF000000)),
),
);
},
separatorBuilder: (BuildContext context, int index) {
print("separatorBuilder--->" + index.toString());
return new Divider(
color: new Color(0xFF888888),
);
},
);
}
}
运行效果如下:

而且从打印中也可以看到分隔线并没有占据子组件空间,它的 position 跟子组件的 position 是一样的:

还有一种构造方法 ListView.custom() 这个暂时还没有去研究。水平方向的 ListView 很简单,只需要将 scrollDirection 设置为 Axis.horizontal 就行,简单贴个效果:

3 总结
ListView 在开发中用得非常多,通常的场景是通过网络请求到一堆数据,然后通过 ListView 分页加载,这种下拉刷新和上拉加载等今后学到网络请求时再研究,应该有前辈都造好轮子了,到时候看看自己能不能实现。
边栏推荐
- setInterval、setTimeout和requestAnimationFrame
- CROSSFORMER: A VERSATILE VISION TRANSFORMER BASED ON CROSS-SCALE ATTENTION
- Leetcode skimming -- teponacci sequence
- JVM之 MinorGC、 MajorGC、 FullGC、
- Cloud management platform: openstack architecture design and detailed interpretation
- 1424. diagonal traversal II
- 分布式和集群分不清,我们讲讲两个厨子炒菜的故事
- UE4 compile a single file (VS and editor start respectively)
- 详细分析PBot挖矿病毒家族行为和所利用漏洞原理,提供蓝军详细防护建议
- Wechat applet rewrites the page function to realize global logging
猜你喜欢

1424. diagonal traversal II

Custom MVC framework implementation

阿里云服务器安装配置redis,无法远程访问

CROSSFORMER: A VERSATILE VISION TRANSFORMER BASED ON CROSS-SCALE ATTENTION

JVM之虚拟机栈之动态链接

Introduction to Chang'an chain data storage and construction of MySQL storage environment

2020-09-29 非商品模板化代码层次 rapidjson库

Making of simple addition calculator based on pyqt5 and QT Designer

User level threads and kernel level threads

Deep Learning-based Automated Delineation of Head and Neck Malignant Lesions from PET Images
随机推荐
Official STM32 chip package download address stm32f10x stm32f40x Download
監控數據源連接池使用情况
Data governance: the solution of data governance in the data Arena
指针函数和函数指针
基於PyQt5和Qt Designer的簡易加法計算器的制作
数据源连接池未关闭的问题 Could not open JDBC Connection for transaction
Leetcode MySQL database topic 178
聊聊你理解的线程与并发
Caused by: org.apache.xerces.impl.io.MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8
滑块验证代码
Mysql5.7 installation tutorial in centos7 under Linux
安装Anaconda后启动JupyterLab需要输入密码
JS获取手机型号和系统版本
leetcode MYSQL数据库题目178
Kicad learning notes - shortcut keys
367. 有效的完全平方数-二分法
JVM之 MinorGC、 MajorGC、 FullGC、
Segmentation of Head and Neck Tumours Using Modified U-net
[technology development] development and design of alcohol tester solution
我想要股票开户优惠,怎么得到?还有,在线开户安全么?