文章目录
- 一、List组件简介
- 1、List组件
- 2、ListItem组件
- 3、ListItemGroup组件
- 二、使用ForEach渲染列表
- 三、设置列表分割线
- 四、设置List排列方向
- 五、索引值计算规则
- 六、示例演示
- 1、AlphabetIndexer组件
- 2、代码
- 3、效果
一、List组件简介
在我们常用的手机应用中,经常会见到一些数据列表,如设置页面、通讯录、商品列表等。下图中两个页面都包含列表,“首页”页面中包含两个网格布局,“商城”页面中包含一个商品列表。
列表中都包含一系列相同宽度的列表项,连续、多行呈现同类数据,例如图片和文本。常见的列表有线性列表(List列表)和网格布局(Grid列表)。
为了帮助开发者构建包含列表的应用,ArkUI提供了List组件和Grid组件,开发者使用List和Grid组件能够很轻松的完成一些列表页面。
List是很常用的滚动类容器组件,一般和子组件ListItem一起使用,List列表中的每一个列表项对应一个ListItem组件。
1、List组件
列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。
List(value?:{space?: number | string, initialIndex?: number, scroller?: Scroller})
参数:
参数名 | 参数类型 | 必填 | 参数描述 |
---|---|---|---|
space | number、string | 否 | 子组件主轴方向的间隔。 默认值:0 说明: 设置为除-1外其他负数或百分比时,按默认值显示。 space参数值小于List分割线宽度时,子组件主轴方向的间隔取分割线宽度。 |
initialIndex | number | 否 | 设置当前List初次加载时视口起始位置显示的item的索引值。 默认值:0 说明: 设置为除-1外其他负数或超过了当前List最后一个item的索引值时视为无效取值,无效取值按默认值显示。 |
scroller | Scroller | 否 | 可滚动组件的控制器。用于与可滚动组件进行绑定。 说明: 不允许和其他滚动类组件绑定同一个滚动控制对象。 |
2、ListItem组件
用来展示列表具体item,必须配合List来使用。
ListItem(value?: string)
参数:
参数名 | 参数类型 | 参数描述 |
---|---|---|
selectable | boolean | 当前ListItem元素是否可以被鼠标框选。 说明: 外层List容器的鼠标框选开启时,ListItem的框选才生效。 默认值:true |
swipeAction | { start?: CustomBuilder, end?:CustomBuilder, edgeEffect?: SwipeEdgeEffect, } | 用于设置ListItem的划出组件。 - start: ListItem向右划动时item左边的组件(List垂直布局时)或ListItem向下划动时item上方的组件(List水平布局时)。 - end: ListItem向左划动时item右边的组件(List垂直布局时)或ListItem向上划动时item下方的组件(List水平布局时)。 - edgeEffect: 滑动效果。 说明: start和end对应的@builder函数中顶层必须是单个组件,不能是if/else、ForEach、LazyForEach语句。 |
3、ListItemGroup组件
该组件用来展示列表item分组,宽度默认充满List组件,必须配合List组件来使用。
当ListItemGroup的父组件List的listDirection属性为Axis.Vertical时,不允许设置ListItemGroup组件的height属性。
ListItemGroup的高度为header高度、footer高度和所有ListItem布局后总高度之和。当父组件List的listDirection属性为Axis.Horizontal时,不允许设置ListItemGroup组件的width属性。ListItemGroup的宽度为header宽度、footer宽度和所有ListItem布局后总宽度之和。
当前ListItemGroup内部的ListItem组件不支持编辑、框选、拖拽功能,即ListItem组件的editable、selectable属性不生效。
ListItemGroup(options?: {header?: CustomBuilder, footer?: CustomBuilder, space?: number | string})
参数:
参数名 | 参数类型 | 必填 | 参数描述 |
---|---|---|---|
header | CustomBuilder | 否 | 设置ListItemGroup头部组件。 |
footer | CustomBuilder | 否 | 设置ListItemGroup尾部组件。 |
space | number、string | 否 | 列表项间距。只作用于ListItem与ListItem之间,不作用于header与ListItem、footer与ListItem之间。 |
说明:
ListItemGroup组件不支持设置通用属性aspectRatio。
ListItemGroup组件如果主轴方向是垂直方向时,设置通用属性height属性不生效。
ListItemGroup组件如果主轴方向是水平方向时,设置通用属性width属性不生效。
二、使用ForEach渲染列表
列表往往由多个列表项组成,所以我们需要在List组件中使用多个ListItem组件来构建列表,这就会导致代码的冗余。使用循环渲染(ForEach)遍历数组的方式构建列表,可以减少重复代码。
ForEach接口基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在ForEach父容器组件中的子组件。例如,ListItem组件要求ForEach的父容器组件必须为List组件。
ForEach(
arr: Array,
itemGenerator: (item: Array, index?: number) => void,
keyGenerator?: (item: Array, index?: number): string => string
)
三、设置列表分割线
List组件子组件ListItem之间默认是没有分割线的,部分场景子组件ListItem间需要设置分割线,这时候您可以使用List组件的divider属性。divider属性包含四个参数:
- strokeWidth: 分割线的线宽。
- color: 分割线的颜色。
- startMargin:分割线距离列表侧边起始端的距离。
- endMargin: 分割线距离列表侧边结束端的距离。
endMargin +startMargin 不能超过列宽度。
startMargin和endMargin不支持设置百分比。
List的分割线画在主轴方向两个子组件之间,第一个子组件上方和最后一个子组件下方不会绘制分割线。
多列模式下,ListItem与ListItem之间的分割线起始边距从每一列的交叉轴方向起始边开始计算,其他情况从List交叉轴方向起始边开始计算。
四、设置List排列方向
List组件里面的列表项默认是按垂直方向排列的,如果您想让列表沿水平方向排列,您可以将List组件的listDirection属性设置为Axis.Horizontal。
listDirection参数类型是Axis,定义了以下两种类型:
- Vertical(默认值):子组件ListItem在List容器组件中呈纵向排列。
- Horizontal:子组件ListItem在List容器组件中呈横向排列。
五、索引值计算规则
List的子组件的索引值计算规则:
- 按子组件的顺序依次递增。
- if/else语句中,只有条件成立的分支内的子组件会参与索引值计算,条件不成立的分支内子组件不计算索引值。
- ForEach/LazyForEach语句中,会计算展开所有子节点索引值。
- if/else/ForEach/LazyForEach发生变化以后,会更新子节点索引值。
- ListItemGroup作为一个整体计算一个索引值,ListItemGroup内部的ListItem不计算索引值。
- List子组件的visibility属性设置为Hidden或None依然会计算索引值。
- List子组件的visibility属性设置为None时不显示,但该子组件上下的space还会生效。
六、示例演示
List组件结合AlphabetIndexer实现汽车之家选车页面布局
1、AlphabetIndexer组件
可以与容器组件联动用于按逻辑结构快速定位容器显示区域的组件。
AlphabetIndexer(value: {arrayValue: Array<string>, selected: number})
参数:
参数名 | 参数类型 | 必填 | 参数描述 |
---|---|---|---|
arrayValue | Array | 是 | 字母索引字符串数组,不可设置为空。 |
selected | number | 是 | 初始选中项索引值,若超出索引值范围,则取默认值0。 |
2、代码
const alphabets = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
interface CarItemInterface {
title: string
}
interface CarInterface {
alphabet: string,
carItem: CarItemInterface[]
}
@Entry
@Component
struct CarListIndex {
@State selectedIndex: number = 0
private listScroller: Scroller = new Scroller()
@State carList: CarInterface[] = [{
alphabet: "A",
carItem: [
{
title: "奥迪"
},
{
title: "奥拓"
},
{
title: "爱驰"
},
{
title: "ATS"
},
{
title: "AIM"
},
{
title: "阿尔特"
},
]
},
{
alphabet: "B",
carItem: [
{
title: "奔驰"
},
{
title: "比亚迪"
},
{
title: "宝马"
},
{
title: "保时捷"
},
{
title: "北京"
},
{
title: "标致"
},
]
},
{
alphabet: "C",
carItem: [
{
title: "长安"
},
{
title: "长城"
},
{
title: "曹操汽车"
},
{
title: "成功汽车"
},
{
title: "北京"
},
{
title: "标致"
},
]
},
{
alphabet: "D",
carItem: [
{
title: "大众"
},
{
title: "东风"
},
{
title: "Ds"
},
{
title: "大运"
},
{
title: "东南"
},
{
title: "大帝"
},
]
},
{
alphabet: "E",
carItem: [
{
title: "e.GO"
},
{
title: "Elek"
},
]
},
{
alphabet: "F",
carItem: [
{
title: "丰田"
},
{
title: "福特"
},
{
title: "福田"
},
{
title: "法拉利"
},
{
title: "福地"
},
{
title: "菲亚特"
},
]
}
]
//自定义组件内自定义构建函数
@Builder itemHead(text: string) {
Text(text)
.fontSize(20)
.backgroundColor(0xEEEEEE)
.width("100%")
.padding(10)
}
build() {
Column() {
Stack({ alignContent: Alignment.End }) {
Column() {
List({ scroller: this.listScroller }) {
ForEach(this.carList, (item: CarInterface) => {
ListItemGroup({ header: this.itemHead(item.alphabet) }) {
ForEach(item.carItem, (pro: CarItemInterface) => {
ListItem() {
Text(pro.title)
.fontSize(16)
.padding(10)
.width("100%")
}
})
}
})
}
.onScrollIndex((index: number) => {
this.selectedIndex = index
})
.sticky(StickyStyle.Header)
}.height('100%')
.width('100%')
AlphabetIndexer({ arrayValue: alphabets, selected: 0 })
.selected(this.selectedIndex)
.onSelect((index) => {
this.listScroller.scrollToIndex(index)
})
}
}
.width('100%')
.height('100%')
}
}