flutter中ListView的详细讲解
程序员文章站
2022-03-01 20:57:33
1.ListView的简单介绍 ListView是最常用的可以滚动组件之一, 它可以沿一个方向进行线性排列所有的子组件。 下面是ListView的属性值介绍: scrollDirection:列表的滚动方向, 可选值有Axis的horizontal和vertical, 默认是垂直方向上滚动。 con ......
1.listview的简单介绍
listview是最常用的可以滚动组件之一, 它可以沿一个方向进行线性排列所有的子组件。 下面是listview的属性值介绍: scrolldirection:列表的滚动方向, 可选值有axis的horizontal和vertical, 默认是垂直方向上滚动。 controller:控制器,与列表滚动相关,比如监听列表的滚动事件。 physics: 列表滚动至边缘后继续拖动的物理效果, android与ios效果不同。 android会呈现出一个波纹状(对应clampingscrollphysics), 而ios上有一个回弹的弹性效果(对应bouncingscrollphysics)。 如果你想不同的平台上呈现各自的效果可以使用alwaysscrollablescrollphysics, 它会根据不同平台自动选用各自的物理效果。如果你想禁用在边缘的拖动效果, 那可以使用neverscrollablescrollphysics; shrinkwrap: 该属性将决定列表的长度是否仅包裹其内容的长度。 当listview嵌在一个无限长的容器组件中时, shrinkwrap必须为true,否则flutter会给出警告; padding: 列表内边距; itemextent: 子元素长度。 当列表中的每一项长度是固定的情况下可以指定该值, 有助于提高列表的性能 (因为它可以帮助listview在未实际渲染子元素之前就计算出每一项元素的位置); children: 容纳子元素的组件数组。
2.listtile 属性简介
this.leading, // 内容的==>前置图标 this.title, // 内容的==>标题 this.subtitle, // 内容的==>副标题 this.trailing, // 内容的==>后置图标 this.isthreeline = false, // 内容的==>是否三行显示 this.dense, // 内容的==>直观感受是整体大小 this.contentpadding, // 内容的==>内容内边距 this.enabled = true, // 内容 是否禁用 this.ontap, // item ontap 点击事件 this.onlongpress, // item onlongpress 长按事件 this.selected = false, // item 是否选中状态
3.listview的基本使用
我们做一个新闻列表; 结构非常的简单:有主标题和副标题 title(主标题)和subtitle(subtitle) 我们一起来看看长成什么样子。
class mycont extends statelesswidget { @override widget build(buildcontext context) { return listview(children: <widget>[ listtile( // 主标题 title: text('flutter 由 google 的工程师团队打造,用于创建高性能、跨平台的移动应用', //文字左对齐 textalign: textalign.left, //超出显示省略号 overflow: textoverflow.ellipsis, style: textstyle( //数字必须是double类型的 fontsize: 20.0, // 设置字体的颜色 color: color.fromargb(200, 100, 100, 8) ) ), // 副标题 subtitle: text('你好flutter'), ), listtile( title: text('flutter 由 google 的工程师团队打造,用于创建高性能、跨平台的移动应用'), subtitle: text('你好flutter'), ), ]); } }
4.listview列表设置前置图标
class mycont extends statelesswidget { @override widget build(buildcontext context) { return listview(children: <widget>[ listtile( // 主标题 // 在前面设置图标 leading: icon( //设置图标类型 icons.settings, //0x后面开始 两位ff表示透明度16进制, color: color(0xffffb6c1), //这是图标的大小 size: 30.0 ), // 在后面设置图标 // trailing: icon(icons.accessible), title: text('flutter教程_2021 dart flutter入门实战视频教程132讲', //文字左对齐 textalign: textalign.left, //超出显示省略号 overflow: textoverflow.ellipsis, style: textstyle( fontsize: 20.0, //数字必须是double类型的 // 设置字体的颜色 color: color(0xffffb6c1) ) ), subtitle: text('不管是ios还是android开发都可以在flutter官网上查到安装及使用步骤,这里我就不累述太多'), ), ]); } }
5.设置前置图片
class mycont extends statelesswidget { @override widget build(buildcontext context) { return listview(children: <widget>[ listtile( // 主标题 // 通过leading可以将图片放在前面 leading: image.network( "https://giidu.c/ster/src=http%3a%2f%2ft14.npg"), title: text( 'flutter教程_2021 dart flutter入门实战视频教程132讲', textalign: textalign.left, //文字左对齐 overflow: textoverflow.ellipsis, //超出显示省略号 style: textstyle( fontsize: 20.0, //数字必须是double类型的 // 设置字体的颜色 color: color(0xffffb6c1) ) ), subtitle: text('不管是ios还是android开发都可以在flutter官网上查到安装及使用步骤,这里我就不累述太多'), ), ]); } }
6.垂直列表
class mycont extends statelesswidget { @override widget build(buildcontext context) { return listview(children: <widget>[ container( width: 750.0, height: 200.0, color:color(0xffffb6c1), // 外边距 左上右下,跟css不一样哈 margin: edgeinsets.fromltrb(10, 10, 10, 0), ), container( width: 750.0, height: 200.0, color: color(0xffffb6c1), // 外边距 左上右下,跟css不一样哈 margin: edgeinsets.fromltrb(10, 10, 10, 0), ) ]); } }
7.水平排列
class mycont extends statelesswidget { @override widget build(buildcontext context) { return container( height: 200.0, child:new listview( // 水平排列 scrolldirection: axis.horizontal, children: <widget>[ container( width: 220.0, height: 200.0, color: color(0xffffb6c1), // 外边距 左上右下,跟css不一样哈 margin: edgeinsets.fromltrb(10, 10, 10, 0), ), container( width: 220.0, height: 200.0, color: color(0xffffb6c1), // 外边距 左上右下,跟css不一样哈 margin: edgeinsets.fromltrb(10, 10, 10, 0), ), container( width: 220.0, height: 200.0, color: color(0xffffb6c1), // 外边距 左上右下,跟css不一样哈 margin: edgeinsets.fromltrb(10, 10, 10, 0), ), ] ) ); } }
8.动态列表
在项目的实际开发过程中; 我们会有很多的列表; 我们想将listview中children中的代码封装成为一个函数。 方便后期的管理
class myapp extends statelesswidget { @override widget build(buildcontext context) { return materialapp( home: scaffold(appbar: appbar(title: text('首页')), body: mycont()), //设置顶部的颜色 theme: themedata(primaryswatch: colors.yellow), ); } } class mycont extends statelesswidget { // lis里面的数据必须是widget组件; // _backdatalist方法下划线开头,表示当前这个类私有的。 list<widget> _backdatalist() { return [ listtile( title: text('我是新闻标题1'), ), listtile( title: text('我是新闻标题2'), ), listtile( title: text('我是新闻标题3'), ), listtile( title: text('我是新闻标题4'), ) ]; } @override widget build(buildcontext context) { return listview(children: this._backdatalist()); } }
9.往数组中添加数据进行循环
class mycont extends statelesswidget { // lis里面的数据必须是widget组件; // _backdatalist方法下划线开头,表示当前这个类私有的。 list<widget>_backdatalist() { // 声明了一个数组,里面的数据类型是widget list<widget> list = []; for (var i = 0; i < 10; i++) { list.add(listtile( title: text('我是新闻标题$i'), )); } return list; } @override widget build(buildcontext context) { return listview(children: this._backdatalist()); } }
10.为什么要使用listview.builder
listview.builder下的两个属性值 itemcount:指定被循环数组的长度 itembuilder:它有2个参数。 itembuilder(conttext, index) { conttext表示的循环的内容 index表示循环的索引值 } 如果itembuilder下是一个封装的函数, 不要添加括号,因为括号表示调用; 直接itembuilder:this.youfunc就可以了 使用listview.builder的优势: listview.builder适合列表项比较多(或者无限)的情况, 只有当子组件真正显示的时候列表才会被创建, 也就说通过该构造函数创建的listview是支持基于sliver的懒加载模型的。 也就是说使用listview.builder可以提升性能。 下面我们将会使用listview.builder来创建一个列表
在lib目录下创建一个res 在res目录下创建demo.dart demo.dart文件下有数据的哈 import 'res/demo.dart'; list listdata = [ { 'title': 'python 创作季,秀出你的 python 文章 } ] 后面使用listdata就可以直接获取数据了哈 class mycont extends statelesswidget { @override widget build(buildcontext context) { return listview.builder( // itemcount:指定该数组的长度 itemcount: listdata.length, //itembuilder 会进行循环遍历 itembuilder: (conttext, index) { return listtile( title: text(listdata[index]['title']), //还有很多的属性xxxx........ ); }, ); } }
前面我们说了,使用listview.builder可以提高性能; 但是我们发现了itembuilder下如果有很多属性的话; 那么就会变得非常的臃肿的; 后期是不利于我们维护; 那么我们能不能将 itembuilder中的抽离出去了? 经过我的查询文档发现是可以的 请看下面:
11.将itembuilder中的属性抽离出去
我们可以将原来itembuilder下的代码 封装成为一个方法放置在自定义的_getlistdata下; 方便我们后期的维护以及修改
class mycont extends statelesswidget { //自定义的方法 widget _getlistdata(conttext, index){ return listtile( title: text(listdata[index]['title']), ); } @override widget build(buildcontext context) { return listview.builder( // itemcount:指定该数组的长度 itemcount: listdata.length, //this._getlistdata是不需要加括号的; // 我们这里表示的复制该方法 // this._getlistdata()表示的是直接去调用这个方法 itembuilder:this._getlistdata ); } }
12.listview children与listview.builder的区别
通过前面的例子, 我们可以发现listview有默认构造函数。 listview默认构造函数有一个children参数, children接受一个widget列表[list], 通过children参数的形式接受的子组件列表。 这种方式需要将所有的children都提前创建好; 因此需要提前做大量的工作; 所以:这种形式只适合少量的子组件的情况 listview.builder listview.builder适合列表项比较多(或者无限)的情况, 只有当子组件真正显示的时候列表才会被创建, 也就说通过该构造函数创建的listview是支持基于sliver的懒加载模型的。
13.制作一个好看的列表
我们将使用后置图标trailing这个属性来完成图片后置。 同时我们将给一个容器组件container; 容器组件的宽高来限制图片的大小; 我们将会对图片进行裁剪,
在lib目录下创建一个res 在res目录下创建demo.dart demo.dart文件下有数据的哈 import 'res/demo.dart'; list listdata = [ { 'title': 'python 创作季,秀出你的 python 文章 } ] class mycont extends statelesswidget { // lis里面的数据必须是widget组件; // _backdatalist方法下划线开头,表示当前这个类私有的。 list<widget> _backdatalist() { var temteplelist = listdata.map((value) { return listtile( title: text( value['title'], // 超出显示省略号 overflow: textoverflow.ellipsis, style: textstyle(fontsize: 16.0, color: color(0xff86909c)), ), subtitle: text( value['cont'], overflow: textoverflow.ellipsis, style: textstyle(fontsize: 13.0, color: color(0xff86909c)), ), trailing: container( width: 90.0, //容器宽 height: 70.0, //容器高 decoration: boxdecoration( borderradius: borderradius.circular(4.0), image: decorationimage( image: networkimage( value['img'], ), alignment: alignment.topleft, //左上角居中 fit: boxfit.cover, //裁剪,充满整个容器。不会变形 ) ) ) ); }); // 转化成为一个数组 return temteplelist.tolist(); } @override widget build(buildcontext context) { return listview(children: this._backdatalist()); } }