List

About 10 min

List

说明: 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。

权限列表

子组件

包含ListItem子组件。

接口

List(value:{space?: number, initialIndex?: number})

  • 参数

    参数名

    参数类型

    必填

    默认值

    参数描述

    space

    number

    0

    列表项间距。

    initialIndex

    number

    0

    设置当前List初次加载时视口起始位置显示的item,即显示第一个item,如设置的序号超过了最后一个item的序号,则设置不生效。

属性

名称

参数类型

默认值

描述

listDirection

Axis

Vertical

设置List组件排列方向参照Axis枚举说明。

divider

{

strokeWidth: Length,

color?:Color,

startMargin?: Length,

endMargin?: Length

}

-

用于设置ListItem分割线样式,默认无分割线。

strokeWidth: 分割线的线宽。

color: 分割线的颜色。

startMargin: 分割线距离列表侧边起始端的距离。

endMargin: 分割线距离列表侧边结束端的距离。

editMode

boolean

false

声明当前List组件是否处于可编辑模式。

edgeEffect

EdgeEffect

Spring

滑动效果,目前支持的滑动效果参见EdgeEffect的枚举说明。

chainAnimation

boolean

false

用于设置当前list是否启用链式联动动效,开启后列表滑动以及顶部和底部拖拽时会有链式联动的效果。链式联动效果:list内的list-item间隔一定距离,在基本的滑动交互行为下,主动对象驱动从动对象进行联动,驱动效果遵循弹簧物理动效。

  • false:不启用链式联动。
  • true:启用链式联动。
  • EdgeEffect枚举说明

    名称

    描述

    Spring

    弹性物理动效,滑动到边缘后可以根据初始速度或通过触摸事件继续滑动一段距离,松手后回弹。

    None

    滑动到边缘后无效果。

事件

名称

功能描述

onItemDelete(index: number) => boolean

列表项删除时触发。

onScrollIndex(firstIndex: number, lastIndex: number) => void

当前列表显示的起始位置和终止位置发生变化时触发。

onItemDragEnter(callback: (event: ItemDragInfo) => void)

绑定后,拖拽在可放置组件范围内移动时,触发回调。

  • itemIndex: 当前被拖拽的ListItem原本的索引。
  • insertIndex: 拖动当前ListItem插入List后的索引。
说明:

当监听了onDrop事件时,此事件才有效。

onItemDragMove(callback: (event: ItemDragInfo, itemIndex: number, insertIndex: number) => void)

绑定后,拖拽在可放置组件范围内移动时,触发回调。

  • itemIndex: 当前被拖拽的ListItem原本的索引。
  • insertIndex: 拖动当前ListItem插入List后的索引。
说明:

当监听了onDrop事件时,此事件才有效。

onItemDragLeave(callback: (event: ItemDragInfo, itemIndex: number) => void)

绑定后,拖拽离开组件范围内时,触发回调。

  • itemIndex: 当前被拖拽的ListItem原本的索引。
说明:

当监听了onDrop事件时,此事件才有效。

onItemDragStart(callback: (event: ItemDragInfo, itemIndex: number) => CustomBuilder)

绑定后,第一次拖拽ListItem时,触发回调。

  • itemIndex: 当前被拖拽的ListItem原本的索引。
  • 返回值:被拖拽ListItem的浮动UI布局。
说明:

当监听了onDrop事件时,此事件才有效。

onItemDrop(callback: (event: ItemDragInfo, itemIndex: number, insertIndex: number,isSuccess: boolean) => void)

绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发此回调。

  • itemIndex: 当前被拖拽的ListItem原本的索引。
  • insertIndex: 拖动当前ListItem插入List后的索引。
  • isSuccess: 拖拽释放时插入是否成功。
说明:

当监听了onDrop事件时,此事件才有效。

说明: List使能可编辑模式需配合onItemDelete事件和ListItem的editable属性,即可编辑模式实现删除列表项功能,需满足以下条件:

  • editMode属性设置为true。
  • 绑定onItemDelete事件,且事件回调返回true。
  • ListItem的editable属性设置为true。 实现ListItem拖拽,需满足以下条件:
  • editMode属性设置为true。
  • 绑定onItemDragStart事件,且事件回调中返回浮动UI布局。
  • ItemDragInfo对象说明

    属性名称

    属性类型

    描述

    x

    number

    拖拽点的横坐标。

    y

    number

    拖拽点的纵坐标。

示例

@Entry
@Component
struct ListExample {
  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  @State editFlag: boolean = false

  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      Column() {
        List({ space: 20, initialIndex: 0 }) {
          ForEach(this.arr, (item) => {
            ListItem() {
              Text('' + item)
                .width('100%').height(100).fontSize(16)
                .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)
            }.editable(true)
          }, item => item)
        }
        .listDirection(Axis.Vertical) // 排列方向
        .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线
        .edgeEffect(EdgeEffect.None) // 滑动到边缘无效果
        .chainAnimation(false) // 联动特效关闭
        .onScrollIndex((firstIndex: number, lastIndex: number) => {
          console.info('first' + firstIndex)
          console.info('last' + lastIndex)
        })
        .editMode(this.editFlag)
        .onItemDelete((index: number) => {
          console.info(this.arr[index] + 'Delete')
          this.arr.splice(index, 1)
          console.info(JSON.stringify(this.arr))
          this.editFlag = false
          return true
        }).width('90%')
      }.width('100%')

      Button('edit list')
        .onClick(() => {
          this.editFlag = !this.editFlag
        }).margin({ top: 5, left: 20 })
    }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding({ top: 5 })
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

@Entry
@Component
struct DragListExample {
  @State number1: string[] = ['0', '1', '2']
  @State number2: string[] = ['one', 'two', 'three']
  @State text: string = ''
  @State bool1: boolean = false
  @State bool2: boolean = false

  @Builder pixelMapBuilder() {
    Text('-1')
      .width('100%').height(100).fontSize(16)
      .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)
  }

  build() {
    Column() {
      List() {
        ForEach(this.number1, (item) => {
          ListItem() {
            Text('' + item)
              .width('100%').height(100).fontSize(16)
              .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xF666FF)
          }
        }, item => item)
      }
      .editMode(true)
      .width('90%').divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 })
      .onItemDelete((index: number) => {
        console.info(this.Number1[index] + 'Delete')
        this.Number1.splice(index, 1)
        console.info(JSON.stringify(this.Number1))
        return true
      })
      .onItemDragStart((event: ItemDragInfo, itemIndex: number) => {
        this.bool1 = true
        this.text = this.number1[itemIndex]
        console.log("List1 onItemDragStart, itemIndex:" + itemIndex + ",  ItemDragInfo:"+`${JSON.stringify(event)}`)
        return this.pixelMapBuilder
      })
      .onItemDragEnter((event: ItemDragInfo) => {
        console.log("List1 onItemDragEnter")
      })
      .onItemDragMove((event: ItemDragInfo, itemIndex: number, insertIndex: number) => {
        console.log("List1 onItemDragMove, itemIndex:" + itemIndex + ", insertIndex:" + insertIndex)
      })
      .onItemDragLeave((event: ItemDragInfo, itemIndex: number) => {
        console.log("List1 onItemDragLeave, itemIndex:" + itemIndex)
      })
      .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => {
        if (isSuccess) {
          if (this.bool2) {
            this.number2.splice(itemIndex, 1)
            this.number1.splice(insertIndex, 0, this.text)
            this.bool1 = false
            this.bool2 = false
          } else if (this.bool1) {
            this.number1.splice(itemIndex, 1)
            this.number1.splice(insertIndex, 0, this.text)
            this.bool1 = false
            this.bool2 = false
          }
        }
        console.log("List1 onItemDrop, itemIndex:" + itemIndex + ", insertIndex:" + insertIndex + ", isSuccess:" + isSuccess)
      })
      Divider().strokeWidth(5).color(0x2788D9).lineCap(LineCapStyle.Round).margin(20)
      List() {
        ForEach(this.Number2, (item) => {
          ListItem() {
            Text('' + item)
              .width('100%').height(100).fontSize(16)
              .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFF888)
          }
        }, item => item)
      }
      .edgeEffect(EdgeEffect.None)
      .width('90%')
      .editMode(true)
      .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 })
      .onItemDragStart((event: ItemDragInfo, itemIndex: number) => {
        this.bool2 = true
        this.text = this.number2[itemIndex]
        console.log("List2 onItemDragStart, itemIndex:" + itemIndex)
        return this.pixelMapBuilder
      })
      .onItemDragEnter((event: ItemDragInfo) => {
        console.log("List2 onItemDragEnter")
      })
      .onItemDragMove((event: ItemDragInfo, itemIndex: number, insertIndex: number) => {
        console.log("List2 onItemDragMove, itemIndex:" + itemIndex + ", insertIndex:" + insertIndex)
      })
      .onItemDragLeave((event: ItemDragInfo, itemIndex: number) => {
        console.log("List2 onItemDragLeave, itemIndex:" + itemIndex)
      })
      .onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => {
        if (isSuccess) {
          if (this.bool1) {
            this.number1.splice(itemIndex, 1)
            this.number2.splice(insertIndex, 0, this.text)
            this.bool1 = false
            this.bool2 = false
          } else if (this.bool2) {
            this.number2.splice(itemIndex, 1)
            this.number2.splice(insertIndex, 0, this.text)
            this.bool1 = false
            this.bool2 = false
          }
        }
        console.log("List2 onItemDrop, itemIndex:" + itemIndex + ", insertIndex:" + insertIndex + ", isSuccess:" + isSuccess)
      })
    }.width('100%').height('100%').backgroundColor(0xE600000).padding({ top: 25 })
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113