列表(List)是一种复杂容器,具有下列特点: (1)列表项(ListItem)数量过多超出屏幕后,会自动提供滚动功能 (2)列表项(ListItem)既可以纵向排列,也可以横向排列 (3)List组件支持使用条件渲染、循环渲染、懒加载等渲染控制
1.布局和约束
列表作为一种容器,会自动按其滚动方向排列子组件,向列表中添加组件或从列表中移除组件会重新排列子组件。
如下图所示,在垂直列表中,List按垂直方向自动排列ListItemGroup或ListItem。
ListItemGroup用于列表数据的分组展示,其子组件也是ListItem。ListItem表示单个列表项,可以包含单个子组件。
必须注意的是,List的子组件必须是ListItemGroup或ListItem,ListItem和ListItemGroup必须配合List来使用。
(1)布局
List除了提供垂直和水平布局能力、超出屏幕时可以滚动的自适应延伸能力之外,还提供了自适应交叉轴方向上排列个数的布局能力。 利用垂直布局能力可以构建单列或者多列垂直滚动列表,如下图所示。
利用水平布局能力可以是构建单行或多行水平滚动列表,如下图所示。
(2)约束
列表的主轴方向是指子组件列的排列方向,也是列表的滚动方向。垂直于主轴的轴称为交叉轴,其方向与主轴方向相互垂直。
如下图所示,垂直列表的主轴是垂直方向,交叉轴是水平方向;水平列表的主轴是水平方向,交叉轴是垂直方向。
如果List组件主轴或交叉轴方向设置了尺寸,则其对应方向上的尺寸为设置值。 如果List组件主轴方向没有设置尺寸,当List子组件主轴方向总尺寸小于List的父组件尺寸时,List主轴方向尺寸自动适应子组件的总尺寸。 如下图所示,一个垂直列表B没有设置高度时,其父组件A高度为200vp,若其所有子组件C的高度总和为150vp,则此时列表B的高度为150vp。
如果子组件主轴方向总尺寸超过List父组件尺寸时,List主轴方向尺寸适应List的父组件尺寸。 如下图所示,同样是没有设置高度的垂直列表B,其父组件A高度为200vp,若其所有子组件C的高度总和为300vp,则此时列表B的高度为200vp。
List组件交叉轴方向在没有设置尺寸时,其尺寸默认自适应父组件尺寸。
2.开发布局
(1)设置主轴方向
List组件主轴默认是垂直方向,即默认情况下不需要手动设置List方向,就可以构建一个垂直滚动列表。 若是水平滚动列表场景,将List的listDirection属性设置为Axis.Horizontal即可实现。listDirection默认为Axis.Vertical,即主轴默认是垂直方向。
Column() {
List() {
ForEach([1,2,3,4,5,6,7,8],(item:number)=>{
ListItem() {
Text(`content:${item}`)
}
})
}.listDirection(Axis.Horizontal).height(100).width('100%')
}.width('100%')
(2)设置交叉轴布局
List组件的交叉轴布局可以通过lanes和alignListItem属性进行设置,lanes属性用于确定交叉轴排列的列表项数量,alignListItem用于设置子组件在交叉轴方向的对齐方式。
1)lanes属性的取值类型是"number"
Column() {
List() {
ForEach([1,2,3,4,5,6,7,8],(item:number)=>{
ListItem() {
Text(`content:${item}`)
}
})
}.lanes(2).width('100%').height('100%').alignListItem(ListItemAlign.Start)
}.width('100%')
2)lanes属性的取值类型是"LengthConstrain",表示会根据LengthConstrain与List组件的尺寸自适应决定行或列数。
@Entry
@Component
struct Index {
@State egLanes: LengthConstrain = { minLength: 200, maxLength: 300 }
build() {
Column() {
List() {
ForEach([1,2,3,4,5,6,7,8],(item:number)=>{
ListItem() {
Text(`content:${item}`)
}
})
}.lanes(this.egLanes).width(450).height('100%').alignListItem(ListItemAlign.End)
}.width('100%')
}
}
例如,假设在垂直列表中设置了lanes的值为{ minLength: 200, maxLength: 300 }。此时,
当List组件宽度为300vp时,由于minLength为200vp,此时列表为一列。 当List组件宽度变化至400vp时,符合两倍的minLength,则此时列表自适应为两列。
同样以垂直列表为例,当alignListItem属性设置为ListItemAlign.Center表示列表项在水平方向上居中对齐。alignListItem的默认值是ListItemAlign.Start,即列表项在列表交叉轴方向上默认按首部对齐。
Column() {
List() {
ForEach([1,2,3,4,5,6,7,8],(item:number)=>{
ListItem() {
Text(`content:${item}`)
}
})
}.lanes(this.egLanes).width(450).height('100%').alignListItem(ListItemAlign.Center)
}.width('100%')
3.在列表中显示数据
列表视图垂直或水平显示项目集合,在行或列超出屏幕时提供滚动功能,使其适合显示大型数据集合。在最简单的列表形式中,List静态地创建其列表项ListItem的内容。
Column() {
List() {
ListItem() {
Text('苹果').fontSize(24)
}
ListItem() {
Text('香蕉').fontSize(24)
}
ListItem() {
Text('桃子').fontSize(24)
}
ListItem() {
Text('栗子').fontSize(24)
}
}
.backgroundColor('#FFF1F3F5')
.alignListItem(ListItemAlign.Center).width(300).height(500)
}.width('100%')
由于在ListItem中只能有一个根节点组件,不支持以平铺形式使用多个组件。因此,若列表项是由多个组件元素组成的,则需要将这多个元素组合到一个容器组件内或组成一个自定义组件。
Column() {
List() {
ForEach([1,2,3,4,5],(item:string)=>{
ListItem() {
Row() {
Image($r("app.media.app_icon")).width(50)
Text('数据:'+item)
}.justifyContent(FlexAlign.SpaceBetween).width('100%').margin({
top:10
})
}
})
}.width('80%').height('80%').backgroundColor(Color.Gray)
}.width('100%')
实现的效果如下:
4.自定义列表样式
(1)设置内容间距在初始化列表时,如需在列表项之间添加间距,可以使用space参数。例如,在每个列表项之间沿主轴方向添加10vp的间隔。
Column() {
List({space:10}) {
ForEach([1, 2, 3, 4, 5], (item: string) => {
ListItem() {
Row() {
Text('item:'+item)
}.justifyContent(FlexAlign.Center).width('100%').backgroundColor(Color.Pink)
}
})
}.width('80%').height('80%')
}.width('100%')
(2)添加分隔线
分隔线用来将界面元素隔开,使单个元素更加容易识别。
List提供了divider属性用于给列表项之间添加分隔线。在设置divider属性时,可以通过strokeWidth和color属性设置分隔线的粗细和颜色。
startMargin和endMargin属性分别用于设置分隔线距离列表侧边起始端的距离和距离列表侧边结束端的距离。
class DividerTmp {
strokeWidth: Length = 1
startMargin: Length = 60
endMargin: Length = 10
color: ResourceColor = '#ffe9f0f0'
constructor(strokeWidth: Length, startMargin: Length, endMargin: Length, color: ResourceColor) {
this.strokeWidth = strokeWidth
this.startMargin = startMargin
this.endMargin = endMargin
this.color = color
}
}
@Entry
@Component
struct Index {
@State egDivider: DividerTmp = new DividerTmp(1, 10, 10, '#fc4c5a')
build() {
Column() {
List() {
ForEach([1,2,3],(item:string)=>{
ListItem() {
Row() {
Image($r("app.media.app_icon")).width(50)
Text('数据:'+item)
}.width('100%').height(60).justifyContent(FlexAlign.SpaceBetween).padding({
left:10,
right:10,
})
}
})
}.divider(this.egDivider).width(250).backgroundColor(Color.Pink).borderRadius(10)
}.width('100%').margin({
top:10
})
}
}
实现的效果如下:
对于分隔线,有如下注意点: .分隔线的宽度会使ListItem之间存在一定间隔,当List设置的内容间距小于分隔线宽度时,ListItem之间的间隔会使用分隔线的宽度。 .当List存在多列时,分割线的startMargin和endMargin作用于每一列上。 .List组件的分隔线画在两个ListItem之间,第一个ListItem上方和最后一个ListItem下方不会绘制分隔线。
(3)添加滚动条
在使用List组件时,可通过scrollBar属性控制列表滚动条的显示。scrollBar的取值类型为BarState,当取值为BarState.Auto表示按需显示滚动条。此时,当触摸到滚动条区域时显示控件,可上下拖拽滚动条快速浏览内容,拖拽时会变粗。若不进行任何操作,2秒后滚动条自动消失。
scrollBar属性API version 9及以下版本默认值为BarState.Off,从API version 10版本开始默认值为BarState.Auto。
Column() {
List({space:10}) {
ForEach([1,2,3,4,5,6,7,8,9,10,11],(item:number)=>{
ListItem() {
Row() {
Text('item:'+item)
}.width('100%').height(item*15<20?20:item*15).justifyContent(FlexAlign.Center).backgroundColor(Color.Pink)
}
})
}.width('80%').height('100%').scrollBar(BarState.Auto)
}.width('100%')
截止目前为止,我们学习了List最常见也是最基本的使用。基础部分学完之后,我们再深入学习List的一些比较高级的用法。