1# List 2 3列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。 4 5> **说明:** 6> 7> - 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8> - 该组件回弹的前提是要有滚动。内容小于一屏时,没有回弹效果。 9 10 11## 子组件 12 13仅支持[ListItem](ts-container-listitem.md)、[ListItemGroup](ts-container-listitemgroup.md)子组件。 14 15> **说明:** 16> 17> List的子组件的索引值计算规则: 18> 19> 按子组件的顺序依次递增。 20> 21> if/else语句中,只有条件成立的分支内的子组件会参与索引值计算,条件不成立的分支内子组件不计算索引值。 22> 23> ForEach/LazyForEach语句中,会计算展开所有子节点索引值。 24> 25> [if/else](../../quick-start/arkts-rendering-control.md#条件渲染)、[ForEach](../../quick-start/arkts-rendering-control.md#循环渲染)和[LazyForEach](../../quick-start/arkts-rendering-control.md#数据懒加载)发生变化以后,会更新子节点索引值。 26> 27> ListItemGroup作为一个整体计算一个索引值,ListItemGroup内部的ListItem不计算索引值。 28> 29> List子组件visibility属性设置为Hidden或None依然会计算索引值。 30> 31> List子组件的visibility属性设置为None时不显示,但该子组件上下的space还会生效。 32 33 34## 接口 35 36List(value?:{space?: number | string, initialIndex?: number, scroller?: Scroller}) 37 38从API version 9开始,该接口支持在ArkTS卡片中使用。 39 40**参数:** 41 42| 参数名 | 参数类型 | 必填 | 参数描述 | 43| -------- | -------- | -------- | -------- | 44| space | number \| string | 否 | 子组件主轴方向的间隔。<br/>默认值:0<br/>**说明:** <br/>设置为除-1外其他负数或百分比时,按默认值显示。<br/>space参数值小于List分割线宽度时,子组件主轴方向的间隔取分割线宽度。 | 45| initialIndex | number | 否 | 设置当前List初次加载时视口起始位置显示的item的索引值。<br/>默认值:0<br/>**说明:** <br/>设置为除-1外其他负数或超过了当前List最后一个item的索引值时视为无效取值,无效取值按默认值显示。 | 46| scroller | [Scroller](ts-container-scroll.md#scroller) | 否 | 可滚动组件的控制器。用于与可滚动组件进行绑定。<br/>**说明:** <br/>不允许和其他滚动类组件绑定同一个滚动控制对象。 | 47 48 49## 属性 50 51除支持[通用属性](ts-universal-attributes-size.md)外,还支持以下属性: 52 53| 名称 | 参数类型 | 描述 | 54| -------- | -------- | -------- | 55| listDirection | [Axis](ts-appendix-enums.md#axis) | 设置List组件排列方向。<br/>默认值:Axis.Vertical<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 56| divider | {<br/>strokeWidth: [Length](ts-types.md#length),<br/>color?:[ResourceColor](ts-types.md#resourcecolor),<br/>startMargin?: Length,<br/>endMargin?: Length<br/>} \| null | 设置ListItem分割线样式,不支持设置百分比,默认无分割线。<br/>- strokeWidth: 分割线的线宽。<br/>- color: 分割线的颜色。<br/>- startMargin: 分割线与列表侧边起始端的距离。<br/>- endMargin: 分割线与列表侧边结束端的距离。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>endMargin +startMargin 不能超过列宽度。 <br/>startMargin和endMargin不支持设置百分比。<br/>List的分割线画在主轴方向两个子组件之间,第一个子组件上方和最后一个子组件下方不会绘制分割线。<br/>多列模式下,ListItem与ListItem之间的分割线起始边距从每一列的交叉轴方向起始边开始计算,其他情况从List交叉轴方向起始边开始计算。 | 57| scrollBar | [BarState](ts-appendix-enums.md#barstate) | 设置滚动条状态。<br/>默认值:BarState.Off<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 58| cachedCount | number | 设置列表中ListItem/ListItemGroup的预加载数量,只在[LazyForEach](../../quick-start/arkts-rendering-control.md#数据懒加载)中生效,其中ListItemGroup将作为一个整体进行计算,ListItemGroup中的所有ListItem会一次性全部加载出来。具体使用可参考[减少应用白块说明](../../ui/ui-ts-performance-improvement-recommendation.md#减少应用滑动白块)。<br/>默认值:1<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**说明:** <br/>单列模式下,会在List显示的ListItem前后各缓存cachedCount个ListItem。<br/>多列模式下, 会在List显示的ListItem前后各缓存cachedCount*列数个ListItem。 | 59| editMode<sup>(deprecated)</sup> | boolean | 声明当前List组件是否处于可编辑模式。<br/>从API version9开始废弃。<br/>默认值:false | 60| edgeEffect | [EdgeEffect](ts-appendix-enums.md#edgeeffect) | 设置组件的滑动效果,支持弹簧效果和阴影效果。<br/>默认值:EdgeEffect.Spring<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 61| chainAnimation | boolean | 设置当前List是否启用链式联动动效,开启后列表滑动以及顶部和底部拖拽时会有链式联动的效果。链式联动效果:List内的list-item间隔一定距离,在基本的滑动交互行为下,主动对象驱动从动对象进行联动,驱动效果遵循弹簧物理动效。<br/>默认值:false<br/>- false:不启用链式联动。<br/>- true:启用链式联动。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 62| multiSelectable<sup>8+</sup> | boolean | 是否开启鼠标框选。<br/>默认值:false<br/>- false:关闭框选。<br/>- true:开启框选。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 63| lanes<sup>9+</sup> | number \| [LengthConstrain](ts-types.md#lengthconstrain) | 以列模式为例(listDirection为Axis.Vertical):<br/>lanes用于决定List组件在交叉轴方向按几列布局。<br/>默认值:1<br/>规则如下:<br/>- lanes为指定的数量时,根据指定的数量与List组件的交叉轴尺寸除以列数作为列的宽度。<br/>- lanes设置了{minLength,maxLength}时,根据List组件的宽度自适应决定lanes数量(即列数),保证缩放过程中lane的宽度符合{minLength,maxLength}的限制。其中,minLength条件会被优先满足,即优先保证符合ListItem的交叉轴尺寸符合最小限制。<br/>- lanes设置了{minLength,maxLength},如果父组件交叉轴方向尺寸约束为无穷大时,固定按一列排列,列宽度按显示区域内最大的ListItem计算<br/>- ListItemGroup在多列模式下也是独占一行,ListItemGroup中的ListItem按照List组件的lanes属性设置值来布局。<br/>- lanes设置了{minLength,maxLength}时,计算列数会按照ListItemGroup的交叉轴尺寸计算。当ListItemGroup交叉轴尺寸与List交叉轴尺寸不一致时ListItemGroup中的列数与List中的列数可能不一样。<br/>该接口支持在ArkTS卡片中使用。 | 64| alignListItem<sup>9+</sup> | [ListItemAlign](#listitemalign9枚举说明) | List交叉轴方向宽度大于ListItem交叉轴宽度 * lanes时,ListItem在List交叉轴方向的布局方式,默认为首部对齐。<br/>默认值:ListItemAlign.Start<br/>该接口支持在ArkTS卡片中使用。 | 65| sticky<sup>9+</sup> | [StickyStyle](#stickystyle9枚举说明) | 配合[ListItemGroup](ts-container-listitemgroup.md)组件使用,设置ListItemGroup中header和footer是否要吸顶或吸底。<br/>默认值:StickyStyle.None<br/>该接口支持在ArkTS卡片中使用。<br/>**说明:**<br/>sticky属性可以设置为 StickyStyle.Header \| StickyStyle.Footer 以同时支持header吸顶和footer吸底。 | 66 67## ListItemAlign<sup>9+</sup>枚举说明 68 69该接口支持在ArkTS卡片中使用。 70 71| 名称 | 描述 | 72| ------ | -------------------------------------- | 73| Start | ListItem在List中,交叉轴方向首部对齐。 | 74| Center | ListItem在List中,交叉轴方向居中对齐。 | 75| End | ListItem在List中,交叉轴方向尾部对齐。 | 76 77## StickyStyle<sup>9+</sup>枚举说明 78 79该接口支持在ArkTS卡片中使用。 80 81| 名称 | 描述 | 82| ------ | -------------------------------------- | 83| None | ListItemGroup的header不吸顶,footer不吸底。 | 84| Header | ListItemGroup的header吸顶,footer不吸底。 | 85| Footer | ListItemGroup的footer吸底,header不吸底。 | 86 87> **说明:** 88> 89> List组件[通用属性clip](ts-universal-attributes-sharp-clipping.md)的默认值为true。 90 91## 事件 92 93| 名称 | 功能描述 | 94| -------- | -------- | 95| onItemDelete<sup>(deprecated)</sup>(event: (index: number) => boolean) | 当List组件在编辑模式时,点击ListItem右边出现的删除按钮时触发。<br/>从API version9开始废弃。<br/>- index: 被删除的列表项的索引值。 | 96| onScroll(event: (scrollOffset: number, scrollState: ScrollState) => void) | 列表滑动时触发。<br/>- scrollOffset: 滑动偏移量。<br/>- [scrollState](#scrollstate枚举说明): 当前滑动状态。<br/>使用控制器调用ScrollEdge和ScrollToIndex时不会触发,其余情况有滚动就会触发该事件。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 97| onScrollIndex(event: (start: number, end: number) => void) | 有子组件划入或划出List显示区域时触发。<br/>计算索引值时,ListItemGroup作为一个整体占一个索引值,不计算ListItemGroup内部ListItem的索引值。<br/>- start: 滑动起始位置索引值。<br/>- end: 滑动结束位置索引值。<br/>触发该事件的条件:列表初始化时会触发一次,List显示区域内第一个子组件的索引值或后一个子组件的索引值有变化时会触发。<br/>List的边缘效果为弹簧效果时,在List划动到边缘继续划动和松手回弹过程不会触发onScrollIndex事件。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 98| onReachStart(event: () => void) | 列表到达起始位置时触发。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**说明:** <br>List初始化时如果initialIndex为0会触发一次,List滚动到起始位置时触发一次。List边缘效果为弹簧效果时,划动经过起始位置时触发一次,回弹回起始位置时再触发一次。 | 99| onReachEnd(event: () => void) | 列表到底末尾位置时触发。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。<br/>**说明:** <br/>List边缘效果为弹簧效果时,划动经过末尾位置时触发一次,回弹回末尾位置时再触发一次。 | 100| onScrollFrameBegin<sup>9+</sup>(event: (offset: number, state: ScrollState) => { offsetRemain }) | 列表开始滑动时触发,事件参数传入即将发生的滑动量,事件处理函数中可根据应用场景计算实际需要的滑动量并作为事件处理函数的返回值返回,列表将按照返回值的实际滑动量进行滑动。<br/>\- offset:即将发生的滑动量,单位vp。<br/>\- state:当前滑动状态。<br/>- offsetRemain:实际滑动量,单位vp。<br/>触发该事件的条件:手指拖动List、List惯性划动时每帧开始时触发;List超出边缘回弹、使用滚动控制器的滚动不会触发。<br/>该接口支持在ArkTS卡片中使用。<br/>**说明:** <br/>当listDirection的值为Axis.Vertical时,返回垂直方向滑动量,当listDirection的值为Axis.Horizontal时,返回水平方向滑动量。 | 101| onScrollStart<sup>9+</sup>(event: () => void) | 列表滑动开始时触发。手指拖动列表或列表的滚动条触发的滑动开始时,会触发该事件。使用[Scroller](ts-container-scroll.md#scroller)滑动控制器触发的带动画的滑动,动画开始时会触发该事件。<br/>该接口支持在ArkTS卡片中使用。 | 102| onScrollStop(event: () => void) | 列表滑动停止时触发。手拖动列表或列表的滚动条触发的滑动,手离开屏幕并且滑动停止时会触发该事件;使用[Scroller](ts-container-scroll.md#scroller)滑动控制器触发的带动画的滑动,动画停止会触发该事件。<br/>从API version 9开始,该接口支持在ArkTS卡片中使用。 | 103| onItemMove(event: (from: number, to: number) => boolean) | 列表元素发生移动时触发。<br/>- from: 移动前索引值。<br/>- to: 移动后索引值。 | 104| onItemDragStart(event: (event: ItemDragInfo, itemIndex: number) => ((() => any) \| void) | 开始拖拽列表元素时触发。<br/>- event: 见[ItemDragInfo对象说明](ts-container-grid.md#itemdraginfo对象说明)。<br/>- itemIndex: 被拖拽列表元素索引值。 | 105| onItemDragEnter(event: (event: ItemDragInfo) => void) | 拖拽进入列表元素范围内时触发。<br/>- event: 见[ItemDragInfo对象说明](ts-container-grid.md#itemdraginfo对象说明)。 | 106| onItemDragMove(event: (event: ItemDragInfo, itemIndex: number, insertIndex: number) => void) | 拖拽在列表元素范围内移动时触发。<br/>- event: 见[ItemDragInfo对象说明](ts-container-grid.md#itemdraginfo对象说明)。<br/>- itemIndex: 拖拽起始位置。<br/>- insertIndex: 拖拽插入位置。 | 107| onItemDragLeave(event: (event: ItemDragInfo, itemIndex: number) => void) | 拖拽离开列表元素时触发。<br/>- event: 见[ItemDragInfo对象说明](ts-container-grid.md#itemdraginfo对象说明)。<br/>- itemIndex: 拖拽离开的列表元素索引值。 | 108| onItemDrop(event: (event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => void) | 绑定该事件的列表元素可作为拖拽释放目标,当在列表元素内停止拖拽时触发。<br/>- event: 见[ItemDragInfo对象说明](ts-container-grid.md#itemdraginfo对象说明)。<br/>- itemIndex: 拖拽起始位置。<br/>- insertIndex: 拖拽插入位置。<br/>- isSuccess: 是否成功释放。<br/>**说明:** <br/>跨List拖拽时,当拖拽释放的位置绑定了onItemDrop时会返回true,否则为false。List内部拖拽时,isSuccess为onItemMove事件的返回值。 | 109 110## ScrollState枚举说明 111 112从API version 9开始,该接口支持在ArkTS卡片中使用。 113 114| 名称 | 描述 | 115| ------ | ------------------------- | 116| Idle | 空闲状态。使用控制器提供的方法滚动、拖动滚动条滚动时触发。 | 117| Scroll | 手指拖动状态。使用手指拖动List滚动时触发。 | 118| Fling | 惯性滚动状态。快速划动松手后惯性滚动和划动到边缘回弹时触发。 | 119 120> **说明:** 121> 122> 要使List处于可编辑模式需配合onItemDelete事件和ListItem的editable属性,即可编辑模式实现删除列表项功能,需满足以下条件: 123> 124> - editMode属性设置为true。 125> 126> - 绑定onItemDelete事件,且事件回调返回true。 127> 128> - ListItem的editable属性设置为true。 129> 130> 实现ListItem拖拽,需满足以下条件: 131> 132> - editMode属性设置为true。 133> 134> - 绑定onDragStart事件,且事件回调中返回浮动UI布局。 135 136 137## 示例 138 139```ts 140// xxx.ets 141@Entry 142@Component 143struct ListExample { 144 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 145 @State editFlag: boolean = false 146 147 build() { 148 Stack({ alignContent: Alignment.TopStart }) { 149 Column() { 150 List({ space: 20, initialIndex: 0 }) { 151 ForEach(this.arr, (item) => { 152 ListItem() { 153 Text('' + item) 154 .width('100%').height(100).fontSize(16) 155 .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF) 156 }.editable(true) 157 }, item => item) 158 } 159 .listDirection(Axis.Vertical) // 排列方向 160 .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线 161 .edgeEffect(EdgeEffect.None) // 滑动到边缘无效果 162 .chainAnimation(false) // 联动特效关闭 163 .onScrollIndex((firstIndex: number, lastIndex: number) => { 164 console.info('first' + firstIndex) 165 console.info('last' + lastIndex) 166 }) 167 .editMode(this.editFlag) 168 .onItemDelete((index: number) => { 169 console.info(this.arr[index] + 'Delete') 170 this.arr.splice(index, 1) 171 console.info(JSON.stringify(this.arr)) 172 this.editFlag = false 173 return true 174 }).width('90%') 175 }.width('100%') 176 177 Button('edit list') 178 .onClick(() => { 179 this.editFlag = !this.editFlag 180 }).margin({ top: 5, left: 20 }) 181 }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding({ top: 5 }) 182 } 183} 184``` 185 186 187 188```ts 189// xxx.ets 190@Entry 191@Component 192struct ListLanesExample { 193 @State arr: string[] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"] 194 @State alignListItem: ListItemAlign = ListItemAlign.Start 195 196 build() { 197 Column() { 198 List({ space: 20, initialIndex: 0 }) { 199 ForEach(this.arr, (item) => { 200 ListItem() { 201 Text('' + item) 202 .width('100%') 203 .height(100) 204 .fontSize(16) 205 .textAlign(TextAlign.Center) 206 .borderRadius(10) 207 .backgroundColor(0xFFFFFF) 208 } 209 .border({ width: 2, color: Color.Green }) 210 }, item => item) 211 } 212 .height(300) 213 .width("90%") 214 .editMode(true) 215 .border({ width: 3, color: Color.Red }) 216 .lanes({ minLength: 40, maxLength: 40 }) 217 .alignListItem(this.alignListItem) 218 219 Button("点击更改alignListItem:" + this.alignListItem).onClick(() => { 220 if (this.alignListItem == ListItemAlign.Start) { 221 this.alignListItem = ListItemAlign.Center 222 } else if (this.alignListItem == ListItemAlign.Center) { 223 this.alignListItem = ListItemAlign.End 224 } else { 225 this.alignListItem = ListItemAlign.Start 226 } 227 }) 228 }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding({ top: 5 }) 229 } 230} 231``` 232 233 234 235```ts 236// xxx.ets 237@Entry 238@Component 239struct ListDividerTest { 240 private arr: number[] = [0, 1, 2, 3] 241 242 @Builder header() { 243 Text('header') 244 .width('100%') 245 .height(50) 246 .fontSize(16) 247 .textAlign(TextAlign.Center) 248 .backgroundColor(0xFFEECC) 249 } 250 251 @Builder footer() { 252 Text('footer') 253 .width('100%') 254 .height(40) 255 .fontSize(16) 256 .textAlign(TextAlign.Center) 257 .backgroundColor(0xFFEECC) 258 } 259 260 @Builder item(index: number) { 261 Text('item' + index) 262 .width('100%').height(80) 263 .fontSize(16) 264 .textAlign(TextAlign.Center) 265 } 266 267 build() { 268 Column() { 269 List() { 270 ForEach(this.arr, (item) => { 271 ListItem() { 272 this.item(item) 273 } 274 }, item => item) 275 ListItemGroup({ header: this.header, footer: this.footer }) { 276 ForEach(this.arr, (item) => { 277 ListItem() { 278 this.item(item) 279 } 280 }, item => item) 281 } 282 .divider({ strokeWidth: 2, color: Color.Red, startMargin: 20, endMargin: 10 }) 283 284 ForEach(this.arr, (item) => { 285 ListItem() { 286 this.item(item) 287 } 288 }, item => item) 289 } 290 .lanes(2) 291 .divider({ strokeWidth: 2, color: Color.Red, startMargin: 20, endMargin: 10 }) 292 .margin(10).borderWidth(1) 293 }.width("100%") 294 .height("100%") 295 } 296} 297``` 298 299