1e41f4b71Sopenharmony_ci# Creating a List (List)
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ci## Overview
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ciA list is a container that displays a collection of items. If the list items go beyond the screen, the list can scroll to reveal the content off the screen. The list is applicable for presenting similar data types or data type sets, such as images and text. Some common lists seen in applications are the contacts list, playlist, and shopping list.
7e41f4b71Sopenharmony_ci
8e41f4b71Sopenharmony_ciYou can use lists to easily and efficiently display structured, scrollable information. Specifically, you can provide a single view of rows or columns by arranging the [ListItemGroup](../reference/apis-arkui/arkui-ts/ts-container-listitemgroup.md) or [ListItem](../reference/apis-arkui/arkui-ts/ts-container-listitem.md) child components linearly in a vertical or horizontal direction in the [List](../reference/apis-arkui/arkui-ts/ts-container-list.md) component, or use [ForEach](../quick-start/arkts-rendering-control-foreach.md) to iterate over a group of rows or columns, or mix any number of single views and **ForEach** structures to build a list. The **List** component supports the generation of child components in various [rendering](../quick-start/arkts-rendering-control-overview.md) modes, including conditional rendering, rendering of repeated content, and lazy data loading.
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci## Layout and Constraints
12e41f4b71Sopenharmony_ci
13e41f4b71Sopenharmony_ciA list automatically arranges child components in the direction it scrolls. Adding or removing child components from the list will trigger re-arrangement of the child components.
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ciAs shown in the following figure, in a vertical list, **ListItemGroup** or **ListItem** components are automatically arranged vertically.
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ci**ListItemGroup** is used to display list data by group. Its child component is also **ListItem**. **ListItem** represents a list item, which can contain a single child component.
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci  **Figure 1** Relationships between List, ListItemGroup, and ListItem 
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci![en-us_image_0000001562940589](figures/en-us_image_0000001562940589.png)
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci>**NOTE**
24e41f4b71Sopenharmony_ci>
25e41f4b71Sopenharmony_ci>A **List** component can contain only **ListItemGroup** or **ListItem** as its child components. **ListItemGroup** and **ListItem** must be used together with **List**.
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci### Layout
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ciApart from the aforementioned features, the list is also able to adapt to the number of elements in the cross axis direction.
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ciWhen used in vertical layout, the list can contain one or more scrollable columns, as shown below.
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ci  **Figure 2** Vertical scrolling list (left: one column; right: multiple columns) 
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ci![en-us_image_0000001511580940](figures/en-us_image_0000001511580940.png)
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ciWhen used in horizontal layout, the list can contain one or more scrollable rows, as shown below.
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ci  **Figure 3** Horizontal scrolling list (left: one column; right: multiple columns) 
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci![en-us_image_0000001511421344](figures/en-us_image_0000001511421344.png)
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci**Grid** and **WaterFlow** can also achieve single-column and multi-column layouts. If the layout requires columns of equal width and does not need to span rows or columns, **List** is preferred over **Grid** and WaterFlow.
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ci### Constraints
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ciThe main axis direction of a list refers to the direction in which the child component columns are laid out and in which the list scrolls. An axis perpendicular to the main axis is referred to as a cross axis, and the direction of the cross axis is perpendicular to a direction of the main axis.
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ciAs shown below, the main axis of a vertical list is in the vertical direction, and the cross axis is in the horizontal direction. The main axis of a horizontal list is in the horizontal direction, and the cross axis is in the vertical direction.
52e41f4b71Sopenharmony_ci
53e41f4b71Sopenharmony_ci  **Figure 4** Main axis and cross axis of the list 
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci![en-us_image_0000001562940581](figures/en-us_image_0000001562940581.png)
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ciIf a size is set for the main axis or cross axis of the **List** component, it is used as the size of the component in the corresponding direction.
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ciIf no size is set for the main axis of the **List** component, the size of the **List** component in the main axis direction automatically adapts to the total size of its child components, as long as the total size of the child components in the main axis direction does not exceed the size of the parent component of **List**.
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ciIn the example shown below, no height is set for vertical list B, and the height of its parent component A is 200 vp. If the total height of all child components C is 150 vp, the height of list B is 150 vp.
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ci  **Figure 5** Main axis height constraint example 1 (A: parent component of List; B: List component; C: all child components of List) 
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci![en-us_image_0000001511580956](figures/en-us_image_0000001511580956.png)
66e41f4b71Sopenharmony_ci
67e41f4b71Sopenharmony_ciIf the total size of the child components in the main axis direction is greater than the size of the parent component of **List**, the size of the **List** component in the main axis direction automatically adapts to the size of its parent component.
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ciIn the example shown below, still no height is set for vertical list B, and the height of its parent component A is 200 vp. If the total height of all child components C is 300 vp, the height of list B is 200 vp.
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ci  **Figure 6** Main axis height constraint example 2 (A: parent component of List; B: List component; C: all child components of List) 
72e41f4b71Sopenharmony_ci
73e41f4b71Sopenharmony_ci![en-us_image_0000001511740548](figures/en-us_image_0000001511740548.png)
74e41f4b71Sopenharmony_ci
75e41f4b71Sopenharmony_ciIf no size is set for the cross axis of the **List** component, the size of the **List** component in the cross axis direction automatically adapts to the size of its parent component.
76e41f4b71Sopenharmony_ci
77e41f4b71Sopenharmony_ci
78e41f4b71Sopenharmony_ci## Developing the Layout
79e41f4b71Sopenharmony_ci
80e41f4b71Sopenharmony_ci
81e41f4b71Sopenharmony_ci### Setting the Main Axis Direction
82e41f4b71Sopenharmony_ci
83e41f4b71Sopenharmony_ciBy default, the main axis of the **List** component runs in the vertical direction. This means that you can create a vertical scrolling list without the need to manually set the list direction.
84e41f4b71Sopenharmony_ci
85e41f4b71Sopenharmony_ciTo create a horizontal scrolling list, set the **listDirection** attribute to **Axis.Horizontal**. The default value of **listDirection** is **Axis.Vertical**.
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ci
88e41f4b71Sopenharmony_ci```ts
89e41f4b71Sopenharmony_ciList() {
90e41f4b71Sopenharmony_ci  // ...
91e41f4b71Sopenharmony_ci}
92e41f4b71Sopenharmony_ci.listDirection(Axis.Horizontal)
93e41f4b71Sopenharmony_ci```
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ci
96e41f4b71Sopenharmony_ci### Setting the Cross Axis Layout
97e41f4b71Sopenharmony_ci
98e41f4b71Sopenharmony_ciThe cross axis layout of the **List** component can be set using the **lanes** and **alignListItem** attributes. The **lanes** attribute controls the number of list items along the cross axis, and the **alignListItem** attribute controls the alignment mode of child components along the cross axis.
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ciThe lanes attribute of the **List** component is useful in building a list that auto-adapts the numbers of rows or columns on devices of different sizes. Its value type is number or [LengthConstrain](../reference/apis-arkui/arkui-ts/ts-types.md#lengthconstrain). If you are building a two-column vertical list shown on the right in Figure 2, set the **lanes** attribute to **2**. The default value of **lanes** is **1**.
101e41f4b71Sopenharmony_ci
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci```ts
104e41f4b71Sopenharmony_ciList() {
105e41f4b71Sopenharmony_ci  // ...
106e41f4b71Sopenharmony_ci}
107e41f4b71Sopenharmony_ci.lanes(2)
108e41f4b71Sopenharmony_ci```
109e41f4b71Sopenharmony_ci
110e41f4b71Sopenharmony_ciIf set to a value of the LengthConstrain type, the **lanes** attribute determines the number of rows or columns based on the LengthConstrain settings and the size of the **List** component.
111e41f4b71Sopenharmony_ci
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ci```ts
114e41f4b71Sopenharmony_ci@Entry
115e41f4b71Sopenharmony_ci@Component
116e41f4b71Sopenharmony_cistruct EgLanes {
117e41f4b71Sopenharmony_ci  @State egLanes: LengthConstrain = { minLength: 200, maxLength: 300 }
118e41f4b71Sopenharmony_ci  build() {
119e41f4b71Sopenharmony_ci    List() {
120e41f4b71Sopenharmony_ci      // ...
121e41f4b71Sopenharmony_ci    }
122e41f4b71Sopenharmony_ci    .lanes(this.egLanes)
123e41f4b71Sopenharmony_ci  }
124e41f4b71Sopenharmony_ci}
125e41f4b71Sopenharmony_ci```
126e41f4b71Sopenharmony_ci
127e41f4b71Sopenharmony_ciFor example, if the **lanes** attribute is set to **{ minLength: 200, maxLength: 300 }** for a vertical list, then:
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci- When the list width is 300 vp, the list contains one column, because **minLength** is 200 vp.
130e41f4b71Sopenharmony_ci
131e41f4b71Sopenharmony_ci- When the list width changes to 400 vp, which is twice that of the **minLength** value, the list is automatically adapted to two-column.
132e41f4b71Sopenharmony_ci
133e41f4b71Sopenharmony_ciWith regard to a vertical list, when the **alignListItem** attribute is set to **ListItemAlign.Center**, list items are center-aligned horizontally; when the **alignListItem** attribute is at its default value **ListItemAlign.Start**, list items are aligned toward the start edge of the cross axis in the list.
134e41f4b71Sopenharmony_ci
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ci```ts
137e41f4b71Sopenharmony_ciList() {
138e41f4b71Sopenharmony_ci  // ...
139e41f4b71Sopenharmony_ci}
140e41f4b71Sopenharmony_ci.alignListItem(ListItemAlign.Center)
141e41f4b71Sopenharmony_ci```
142e41f4b71Sopenharmony_ci
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ci## Displaying Data in the List
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ciThe list displays a collection of items horizontally or vertically and can scroll to reveal content off the screen. In the simplest case, a **List** component is statically made up of **ListItem** components.
147e41f4b71Sopenharmony_ci
148e41f4b71Sopenharmony_ci  **Figure 7** Example of a city list 
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci![en-us_image_0000001563060761](figures/en-us_image_0000001563060761.png)
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ci```ts
153e41f4b71Sopenharmony_ci@Entry
154e41f4b71Sopenharmony_ci@Component
155e41f4b71Sopenharmony_cistruct CityList {
156e41f4b71Sopenharmony_ci  build() {
157e41f4b71Sopenharmony_ci    List() {
158e41f4b71Sopenharmony_ci      ListItem() {
159e41f4b71Sopenharmony_ci        Text('Beijing').fontSize(24)
160e41f4b71Sopenharmony_ci      }
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci      ListItem() {
163e41f4b71Sopenharmony_ci        Text('Hangzhou').fontSize(24)
164e41f4b71Sopenharmony_ci      }
165e41f4b71Sopenharmony_ci
166e41f4b71Sopenharmony_ci      ListItem() {
167e41f4b71Sopenharmony_ci        Text('Shanghai').fontSize(24)
168e41f4b71Sopenharmony_ci      }
169e41f4b71Sopenharmony_ci    }
170e41f4b71Sopenharmony_ci    .backgroundColor('#FFF1F3F5')
171e41f4b71Sopenharmony_ci    .alignListItem(ListItemAlign.Center)
172e41f4b71Sopenharmony_ci  }
173e41f4b71Sopenharmony_ci}
174e41f4b71Sopenharmony_ci```
175e41f4b71Sopenharmony_ci
176e41f4b71Sopenharmony_ciEach **ListItem** component can contain only one root child component. Therefore, it does not allow for child components in tile mode. If tile mode is required, encapsulate the child components into a container or create a custom component.
177e41f4b71Sopenharmony_ci
178e41f4b71Sopenharmony_ci  **Figure 8** Example of a contacts list 
179e41f4b71Sopenharmony_ci
180e41f4b71Sopenharmony_ci![en-us_image_0000001511421328](figures/en-us_image_0000001511421328.png)
181e41f4b71Sopenharmony_ci
182e41f4b71Sopenharmony_ciAs shown above, as a list item, each contact has a profile picture and a name. To present it, you can encapsulate **Image** and **Text** components into a **Row** container.
183e41f4b71Sopenharmony_ci
184e41f4b71Sopenharmony_ci
185e41f4b71Sopenharmony_ci```ts
186e41f4b71Sopenharmony_ciList() {
187e41f4b71Sopenharmony_ci  ListItem() {
188e41f4b71Sopenharmony_ci    Row() {
189e41f4b71Sopenharmony_ci      Image($r('app.media.iconE'))
190e41f4b71Sopenharmony_ci        .width(40)
191e41f4b71Sopenharmony_ci        .height(40)
192e41f4b71Sopenharmony_ci        .margin(10)
193e41f4b71Sopenharmony_ci
194e41f4b71Sopenharmony_ci      Text ('Tom')
195e41f4b71Sopenharmony_ci        .fontSize(20)
196e41f4b71Sopenharmony_ci    }
197e41f4b71Sopenharmony_ci  }
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci  ListItem() {
200e41f4b71Sopenharmony_ci    Row() {
201e41f4b71Sopenharmony_ci      Image($r('app.media.iconF'))
202e41f4b71Sopenharmony_ci        .width(40)
203e41f4b71Sopenharmony_ci        .height(40)
204e41f4b71Sopenharmony_ci        .margin(10)
205e41f4b71Sopenharmony_ci
206e41f4b71Sopenharmony_ci      Text ('Tracy')
207e41f4b71Sopenharmony_ci        .fontSize(20)
208e41f4b71Sopenharmony_ci    }
209e41f4b71Sopenharmony_ci  }
210e41f4b71Sopenharmony_ci}
211e41f4b71Sopenharmony_ci```
212e41f4b71Sopenharmony_ci
213e41f4b71Sopenharmony_ci
214e41f4b71Sopenharmony_ci## Iterating List Content
215e41f4b71Sopenharmony_ci
216e41f4b71Sopenharmony_ciCompared with a static list, a dynamic list is more common in applications. You can use [ForEach](../quick-start/arkts-rendering-control-foreach.md) to obtain data from the data source and create components for each data item.
217e41f4b71Sopenharmony_ci
218e41f4b71Sopenharmony_ci For example, when creating a contacts list, you can store the contact name and profile picture data in a **Contact** class structure to the **contacts** array, and nest **ListItem**s in **ForEach**, thereby reducing repeated code needed for tiling similar list items.
219e41f4b71Sopenharmony_ci
220e41f4b71Sopenharmony_ci
221e41f4b71Sopenharmony_ci```ts
222e41f4b71Sopenharmony_ciimport { util } from '@kit.ArkTS'
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ciclass Contact {
225e41f4b71Sopenharmony_ci  key: string = util.generateRandomUUID(true);
226e41f4b71Sopenharmony_ci  name: string;
227e41f4b71Sopenharmony_ci  icon: Resource;
228e41f4b71Sopenharmony_ci
229e41f4b71Sopenharmony_ci  constructor(name: string, icon: Resource) {
230e41f4b71Sopenharmony_ci    this.name = name;
231e41f4b71Sopenharmony_ci    this.icon = icon;
232e41f4b71Sopenharmony_ci  }
233e41f4b71Sopenharmony_ci}
234e41f4b71Sopenharmony_ci
235e41f4b71Sopenharmony_ci@Entry
236e41f4b71Sopenharmony_ci@Component
237e41f4b71Sopenharmony_cistruct SimpleContacts {
238e41f4b71Sopenharmony_ci  private contacts: Array<object> = [
239e41f4b71Sopenharmony_ci    new Contact ('Tom', $r ("app.media.iconA")),
240e41f4b71Sopenharmony_ci    new Contact ('Tracy', $r ("app.media.iconB")),
241e41f4b71Sopenharmony_ci  ]
242e41f4b71Sopenharmony_ci
243e41f4b71Sopenharmony_ci  build() {
244e41f4b71Sopenharmony_ci    List() {
245e41f4b71Sopenharmony_ci      ForEach(this.contacts, (item: Contact) => {
246e41f4b71Sopenharmony_ci        ListItem() {
247e41f4b71Sopenharmony_ci          Row() {
248e41f4b71Sopenharmony_ci            Image(item.icon)
249e41f4b71Sopenharmony_ci              .width(40)
250e41f4b71Sopenharmony_ci              .height(40)
251e41f4b71Sopenharmony_ci              .margin(10)
252e41f4b71Sopenharmony_ci            Text(item.name).fontSize(20)
253e41f4b71Sopenharmony_ci          }
254e41f4b71Sopenharmony_ci          .width('100%')
255e41f4b71Sopenharmony_ci          .justifyContent(FlexAlign.Start)
256e41f4b71Sopenharmony_ci        }
257e41f4b71Sopenharmony_ci      }, (item: Contact) => JSON.stringify(item))
258e41f4b71Sopenharmony_ci    }
259e41f4b71Sopenharmony_ci    .width('100%')
260e41f4b71Sopenharmony_ci  }
261e41f4b71Sopenharmony_ci}
262e41f4b71Sopenharmony_ci```
263e41f4b71Sopenharmony_ci
264e41f4b71Sopenharmony_ciIn the **List** component, **ForEach** can be used to render **ListItemGroup** items as well as **ListItem** items. For details, see [Adding Grouping Support](#adding-grouping-support).
265e41f4b71Sopenharmony_ci
266e41f4b71Sopenharmony_ci
267e41f4b71Sopenharmony_ci## Customizing the List Style
268e41f4b71Sopenharmony_ci
269e41f4b71Sopenharmony_ci
270e41f4b71Sopenharmony_ci### Setting the Spacing
271e41f4b71Sopenharmony_ci
272e41f4b71Sopenharmony_ciWhen initializing a list, you can use the **space** parameter to add spacing between list items. In the following example, a 10vp spacing is added between list items along the main axis:
273e41f4b71Sopenharmony_ci
274e41f4b71Sopenharmony_ci
275e41f4b71Sopenharmony_ci```ts
276e41f4b71Sopenharmony_ciList({ space: 10 }) {
277e41f4b71Sopenharmony_ci  // ...
278e41f4b71Sopenharmony_ci}
279e41f4b71Sopenharmony_ci```
280e41f4b71Sopenharmony_ci
281e41f4b71Sopenharmony_ci
282e41f4b71Sopenharmony_ci### Adding Dividers
283e41f4b71Sopenharmony_ci
284e41f4b71Sopenharmony_ciA divider separates UI items to make them easier to identify. In the following figure, a divider is added between the setting items. Note that since the icons are easy to identify in their own right, the divers do not extend below the icons.
285e41f4b71Sopenharmony_ci
286e41f4b71Sopenharmony_ci  **Figure 9** Using dividers between the setting items 
287e41f4b71Sopenharmony_ci
288e41f4b71Sopenharmony_ci![en-us_image_0000001511580960](figures/en-us_image_0000001511580960.png)
289e41f4b71Sopenharmony_ci
290e41f4b71Sopenharmony_ciTo add dividers between list items, you can use the **divider** attribute together with the following style attributes:<br> **strokeWidth** and **color**: stroke width and color of the diver, respectively.
291e41f4b71Sopenharmony_ci
292e41f4b71Sopenharmony_ci**startMargin** and **endMargin**: distance between the divider and the start edge and end edge of the list, respectively.
293e41f4b71Sopenharmony_ci
294e41f4b71Sopenharmony_ci
295e41f4b71Sopenharmony_ci```ts
296e41f4b71Sopenharmony_ciclass DividerTmp {
297e41f4b71Sopenharmony_ci  strokeWidth: Length = 1
298e41f4b71Sopenharmony_ci  startMargin: Length = 60
299e41f4b71Sopenharmony_ci  endMargin: Length = 10
300e41f4b71Sopenharmony_ci  color: ResourceColor = '#ffe9f0f0'
301e41f4b71Sopenharmony_ci
302e41f4b71Sopenharmony_ci  constructor(strokeWidth: Length, startMargin: Length, endMargin: Length, color: ResourceColor) {
303e41f4b71Sopenharmony_ci    this.strokeWidth = strokeWidth
304e41f4b71Sopenharmony_ci    this.startMargin = startMargin
305e41f4b71Sopenharmony_ci    this.endMargin = endMargin
306e41f4b71Sopenharmony_ci    this.color = color
307e41f4b71Sopenharmony_ci  }
308e41f4b71Sopenharmony_ci}
309e41f4b71Sopenharmony_ci@Entry
310e41f4b71Sopenharmony_ci@Component
311e41f4b71Sopenharmony_cistruct EgDivider {
312e41f4b71Sopenharmony_ci  @State egDivider: DividerTmp = new DividerTmp(1, 60, 10, '#ffe9f0f0')
313e41f4b71Sopenharmony_ci  build() {
314e41f4b71Sopenharmony_ci    List() {
315e41f4b71Sopenharmony_ci      // ...
316e41f4b71Sopenharmony_ci    }
317e41f4b71Sopenharmony_ci    .divider(this.egDivider)
318e41f4b71Sopenharmony_ci  }
319e41f4b71Sopenharmony_ci}
320e41f4b71Sopenharmony_ci```
321e41f4b71Sopenharmony_ci
322e41f4b71Sopenharmony_ciThis example draws a divider with a stroke thickness of 1 vp from a position 60 vp away from the start edge of the list to a position 10 vp away from the end edge of the list. The effect is shown in Figure 9.
323e41f4b71Sopenharmony_ci
324e41f4b71Sopenharmony_ci>**NOTE**
325e41f4b71Sopenharmony_ci>
326e41f4b71Sopenharmony_ci>1. The stroke width of the divider causes some space between list items. If the content spacing set for the list is smaller than the stroke width of the divider, the latter is used instead.
327e41f4b71Sopenharmony_ci>
328e41f4b71Sopenharmony_ci>2. When a list contains multiple columns, the **startMargin** and **endMargin** attributes of the divider apply to each column.
329e41f4b71Sopenharmony_ci>
330e41f4b71Sopenharmony_ci>3. The divider is drawn between list items. No divider is drawn above the first list item and below the last list item.
331e41f4b71Sopenharmony_ci
332e41f4b71Sopenharmony_ci
333e41f4b71Sopenharmony_ci### Adding a Scrollbar
334e41f4b71Sopenharmony_ci
335e41f4b71Sopenharmony_ciWhen the total height (width) of list items exceeds the screen height (width), the list can scroll vertically (horizontally). The scrollbar of a list enables users to quickly navigate the list content, as shown below.
336e41f4b71Sopenharmony_ci
337e41f4b71Sopenharmony_ci  **Figure 10** Scrollbar of a list
338e41f4b71Sopenharmony_ci
339e41f4b71Sopenharmony_ci![en-us_image_0000001511740544](figures/en-us_image_0000001511740544.gif)
340e41f4b71Sopenharmony_ci
341e41f4b71Sopenharmony_ciWhen using the **List** component, you can use the **scrollBar** attribute to control the display of the list scrollbar. The value type of **scrollBar** is [BarState](../reference/apis-arkui/arkui-ts/ts-appendix-enums.md#barstate). When the value is **BarState.Auto**, the scrollbar is displayed as required: It is displayed when the scrollbar area is touched and becomes thicker when being dragged; it automatically disappears after 2 seconds of inactivity.
342e41f4b71Sopenharmony_ci
343e41f4b71Sopenharmony_ciThe default value of the **scrollBar attribute** is **BarState.Off** in API version 9 and earlier versions and **BarState.Auto** since API version 10.
344e41f4b71Sopenharmony_ci```ts
345e41f4b71Sopenharmony_ciList() {
346e41f4b71Sopenharmony_ci  // ...
347e41f4b71Sopenharmony_ci}
348e41f4b71Sopenharmony_ci.scrollBar(BarState.Auto)
349e41f4b71Sopenharmony_ci```
350e41f4b71Sopenharmony_ci
351e41f4b71Sopenharmony_ci
352e41f4b71Sopenharmony_ci## Adding Grouping Support
353e41f4b71Sopenharmony_ci
354e41f4b71Sopenharmony_ciBy allowing data to be displayed in groups in the list, you make the list easier to scan and navigate. Grouping is common in real-world applications. For example, the contacts list below use grouping.
355e41f4b71Sopenharmony_ci
356e41f4b71Sopenharmony_ci  **Figure 11** Contacts list with grouping
357e41f4b71Sopenharmony_ci
358e41f4b71Sopenharmony_ci![en-us_image_0000001511580948](figures/en-us_image_0000001511580948.png)
359e41f4b71Sopenharmony_ci
360e41f4b71Sopenharmony_ciYou can use **ListItemGroup** to group items in the **List** component to build a two-dimensional list.
361e41f4b71Sopenharmony_ci
362e41f4b71Sopenharmony_ciA **List** component allows one or more **ListItemGroup** child components. By default, the width of **ListItemGroup** is equal to that of **List**. When initializing **ListItemGroup**, you can use the **header** parameter to set its header.
363e41f4b71Sopenharmony_ci
364e41f4b71Sopenharmony_ci
365e41f4b71Sopenharmony_ci```ts
366e41f4b71Sopenharmony_ci@Entry
367e41f4b71Sopenharmony_ci@Component
368e41f4b71Sopenharmony_cistruct ContactsList {
369e41f4b71Sopenharmony_ci  
370e41f4b71Sopenharmony_ci  @Builder itemHead(text: string) {
371e41f4b71Sopenharmony_ci    // Header of the list group, corresponding to the group A and B locations.
372e41f4b71Sopenharmony_ci    Text(text)
373e41f4b71Sopenharmony_ci      .fontSize(20)
374e41f4b71Sopenharmony_ci      .backgroundColor('#fff1f3f5')
375e41f4b71Sopenharmony_ci      .width('100%')
376e41f4b71Sopenharmony_ci      .padding(5)
377e41f4b71Sopenharmony_ci  }
378e41f4b71Sopenharmony_ci
379e41f4b71Sopenharmony_ci  build() {
380e41f4b71Sopenharmony_ci    List() {
381e41f4b71Sopenharmony_ci      ListItemGroup({ header: this.itemHead('A') }) {
382e41f4b71Sopenharmony_ci        // Render the repeated list items of group A.
383e41f4b71Sopenharmony_ci      }
384e41f4b71Sopenharmony_ci
385e41f4b71Sopenharmony_ci      ListItemGroup({ header: this.itemHead('B') }) {
386e41f4b71Sopenharmony_ci        // Render the repeated list items of group B.
387e41f4b71Sopenharmony_ci      }
388e41f4b71Sopenharmony_ci    }
389e41f4b71Sopenharmony_ci  }
390e41f4b71Sopenharmony_ci}
391e41f4b71Sopenharmony_ci```
392e41f4b71Sopenharmony_ci
393e41f4b71Sopenharmony_ciIf the structures of multiple **ListItemGroup** components are similar, you can combine the data of these components into an array and use **ForEach** to render them cyclically. For example, in the contacts list, the **contacts** data of each group (for details, see [Iterating List Content](#iterating-list-content)) and the **title** data of the corresponding group are combined and defined as the **contactsGroups** array. Then, with rendering of **contactsGroups** in **ForEach**, a contact list with multiple groups is implemented. For details, see the example in [Adding a Sticky Header](#adding-a sticky-header).
394e41f4b71Sopenharmony_ci
395e41f4b71Sopenharmony_ci## Adding a Sticky Header
396e41f4b71Sopenharmony_ci
397e41f4b71Sopenharmony_ciThe sticky header is a common pattern for keeping the header in the same place on the screen while the user scrolls down the list. As shown in the following figure, when you scroll through group A in the contacts list, the header of group B is always below group A. When you start scrolling through group B, the header of group B is fixed at the top of the screen. After group B has been scrolled to the bottom, the header of group B is replaced by the header of next group.
398e41f4b71Sopenharmony_ci
399e41f4b71Sopenharmony_ciSticky headers not only signify the representation and usage of data in the respective groups, but also help users navigate through a large amount of information, thereby avoiding unnecessary scrolling between the top of the area where the header is located and the area of interest.
400e41f4b71Sopenharmony_ci
401e41f4b71Sopenharmony_ci  **Figure 12** Sticky header 
402e41f4b71Sopenharmony_ci
403e41f4b71Sopenharmony_ci![en-us_image_0000001511740552](figures/en-us_image_0000001511740552.gif)
404e41f4b71Sopenharmony_ci
405e41f4b71Sopenharmony_ciYou can set a sticky header or footer for a **ListItemGroup** component by setting the **sticky** attribute of its parent **List** component.
406e41f4b71Sopenharmony_ci
407e41f4b71Sopenharmony_ciSetting the **sticky** attribute to **StickyStyle.Header** implements a sticky header. To implement a sticky footer, use the **footer** parameter to initialize the footer of **ListItemGroup** and set the **sticky** attribute to **StickyStyle.Footer**.
408e41f4b71Sopenharmony_ci
409e41f4b71Sopenharmony_ci
410e41f4b71Sopenharmony_ci```ts
411e41f4b71Sopenharmony_ciimport { util } from '@kit.ArkTS'
412e41f4b71Sopenharmony_ciclass Contact {
413e41f4b71Sopenharmony_ci  key: string = util.generateRandomUUID(true);
414e41f4b71Sopenharmony_ci  name: string;
415e41f4b71Sopenharmony_ci  icon: Resource;
416e41f4b71Sopenharmony_ci
417e41f4b71Sopenharmony_ci  constructor(name: string, icon: Resource) {
418e41f4b71Sopenharmony_ci    this.name = name;
419e41f4b71Sopenharmony_ci    this.icon = icon;
420e41f4b71Sopenharmony_ci  }
421e41f4b71Sopenharmony_ci}
422e41f4b71Sopenharmony_ciclass ContactsGroup {
423e41f4b71Sopenharmony_ci  title: string = ''
424e41f4b71Sopenharmony_ci  contacts: Array<object> | null = null
425e41f4b71Sopenharmony_ci  key: string = ""
426e41f4b71Sopenharmony_ci}
427e41f4b71Sopenharmony_ciexport let contactsGroups: object[] = [
428e41f4b71Sopenharmony_ci  {
429e41f4b71Sopenharmony_ci    title: 'A',
430e41f4b71Sopenharmony_ci    contacts: [
431e41f4b71Sopenharmony_ci      new Contact('Alice', $r('app.media.iconA')),
432e41f4b71Sopenharmony_ci      new Contact ('Ann', $r ('app.media.iconB')),
433e41f4b71Sopenharmony_ci      new Contact('Angela', $r('app.media.iconC')),
434e41f4b71Sopenharmony_ci    ],
435e41f4b71Sopenharmony_ci    key: util.generateRandomUUID(true)
436e41f4b71Sopenharmony_ci  } as ContactsGroup,
437e41f4b71Sopenharmony_ci  {
438e41f4b71Sopenharmony_ci    title: 'B',
439e41f4b71Sopenharmony_ci    contacts: [
440e41f4b71Sopenharmony_ci      new Contact ('Ben', $r ('app.media.iconD')),
441e41f4b71Sopenharmony_ci      new Contact ('Bryan', $r ('app.media.iconE')),
442e41f4b71Sopenharmony_ci    ],
443e41f4b71Sopenharmony_ci    key: util.generateRandomUUID(true)
444e41f4b71Sopenharmony_ci  } as ContactsGroup,
445e41f4b71Sopenharmony_ci  // ...
446e41f4b71Sopenharmony_ci]
447e41f4b71Sopenharmony_ci@Entry
448e41f4b71Sopenharmony_ci@Component
449e41f4b71Sopenharmony_cistruct ContactsList {
450e41f4b71Sopenharmony_ci  // Define the contactsGroups array.
451e41f4b71Sopenharmony_ci  @Builder itemHead(text: string) {
452e41f4b71Sopenharmony_ci    // Header of the list group, corresponding to the group A and B locations.
453e41f4b71Sopenharmony_ci    Text(text)
454e41f4b71Sopenharmony_ci      .fontSize(20)
455e41f4b71Sopenharmony_ci      .backgroundColor('#fff1f3f5')
456e41f4b71Sopenharmony_ci      .width('100%')
457e41f4b71Sopenharmony_ci      .padding(5)
458e41f4b71Sopenharmony_ci  }
459e41f4b71Sopenharmony_ci  build() {
460e41f4b71Sopenharmony_ci    List() {
461e41f4b71Sopenharmony_ci      // Render the <ListItemGroup> components cyclically. contactsGroups is the data set of contacts and titles of multiple groups.
462e41f4b71Sopenharmony_ci      ForEach(contactsGroups, (itemGroup: ContactsGroup) => {
463e41f4b71Sopenharmony_ci        ListItemGroup({ header: this.itemHead(itemGroup.title) }) {
464e41f4b71Sopenharmony_ci          // Render <ListItem> components cyclically.
465e41f4b71Sopenharmony_ci          if (itemGroup.contacts) {
466e41f4b71Sopenharmony_ci            ForEach(itemGroup.contacts, (item: Contact) => {
467e41f4b71Sopenharmony_ci              ListItem() {
468e41f4b71Sopenharmony_ci                // ...
469e41f4b71Sopenharmony_ci              }
470e41f4b71Sopenharmony_ci            }, (item: Contact) => JSON.stringify(item))
471e41f4b71Sopenharmony_ci          }
472e41f4b71Sopenharmony_ci        }
473e41f4b71Sopenharmony_ci      }, (itemGroup: ContactsGroup) => JSON.stringify(itemGroup))
474e41f4b71Sopenharmony_ci    }.sticky(StickyStyle.Header)  // Set a sticky header.
475e41f4b71Sopenharmony_ci  }
476e41f4b71Sopenharmony_ci}
477e41f4b71Sopenharmony_ci```
478e41f4b71Sopenharmony_ci
479e41f4b71Sopenharmony_ci
480e41f4b71Sopenharmony_ci## Controlling the Scrolling Position
481e41f4b71Sopenharmony_ci
482e41f4b71Sopenharmony_ciIn some cases you may want to control the scrolling position of a list. For example, when there are a huge number of items in the news page list, you may want to allow users to quickly jump to the top or bottom of the list after they have scrolled to a certain point. Below is an example.
483e41f4b71Sopenharmony_ci
484e41f4b71Sopenharmony_ci  **Figure 13** Returning to the top of the list 
485e41f4b71Sopenharmony_ci
486e41f4b71Sopenharmony_ci![en-us_image_0000001511900520](figures/en-us_image_0000001511900520.gif)
487e41f4b71Sopenharmony_ci
488e41f4b71Sopenharmony_ciWhen the **List** component is initialized, you can use the **scroller** parameter to bind a [Scroller](../reference/apis-arkui/arkui-ts/ts-container-scroll.md#scroller) object to control the scrolling of the list. In this example of a news page list, the **scrollToIndex** API of the **Scroller** object is used to scroll the list to the list item with the specified index. This allows the user to return to the top of the list by clicking a specific button.
489e41f4b71Sopenharmony_ci
490e41f4b71Sopenharmony_ciTo start with, create a **Scroller** object **listScroller**.
491e41f4b71Sopenharmony_ci
492e41f4b71Sopenharmony_ci
493e41f4b71Sopenharmony_ci```ts
494e41f4b71Sopenharmony_ciprivate listScroller: Scroller = new Scroller();
495e41f4b71Sopenharmony_ci```
496e41f4b71Sopenharmony_ci
497e41f4b71Sopenharmony_ciThen, use **listScroller** to initialize the **scroller** parameter to bind it with the **List** component. Set **scrollToIndex** to **0**, meaning to return to the top of the list.
498e41f4b71Sopenharmony_ci
499e41f4b71Sopenharmony_ci
500e41f4b71Sopenharmony_ci```ts
501e41f4b71Sopenharmony_ciStack({ alignContent: Alignment.Bottom }) {
502e41f4b71Sopenharmony_ci  // use listScroller to initialize the scroller parameter to bind it with the <List> component.
503e41f4b71Sopenharmony_ci  List({ space: 20, scroller: this.listScroller }) {
504e41f4b71Sopenharmony_ci    // ...
505e41f4b71Sopenharmony_ci  }
506e41f4b71Sopenharmony_ci
507e41f4b71Sopenharmony_ci  Button() {
508e41f4b71Sopenharmony_ci    // ...
509e41f4b71Sopenharmony_ci  }
510e41f4b71Sopenharmony_ci  .onClick(() => {
511e41f4b71Sopenharmony_ci    // Specify where e to jump when the specific button is clicked, which is the top of the list in this example.
512e41f4b71Sopenharmony_ci    this.listScroller.scrollToIndex(0)
513e41f4b71Sopenharmony_ci  })
514e41f4b71Sopenharmony_ci}
515e41f4b71Sopenharmony_ci```
516e41f4b71Sopenharmony_ci
517e41f4b71Sopenharmony_ci
518e41f4b71Sopenharmony_ci## Responding to the Scrolling Position
519e41f4b71Sopenharmony_ci
520e41f4b71Sopenharmony_ciMany applications need to listen for the scrolling position change of the list and respond. For example, with regard to a contacts list, if scrolling spans more than one group, the alphabetical index bar at one side of the list also needs to be updated to highlight the letter corresponding to the current group.
521e41f4b71Sopenharmony_ci
522e41f4b71Sopenharmony_ciAnother common example is a scrolling list working with a multi-level index bar, as in the case of a product category page in a shopping application.
523e41f4b71Sopenharmony_ci
524e41f4b71Sopenharmony_ci**Figure 14** Alphabetical index bar's response to contacts list scrolling 
525e41f4b71Sopenharmony_ci
526e41f4b71Sopenharmony_ci![en-us_image_0000001563060769](figures/en-us_image_0000001563060769.gif)
527e41f4b71Sopenharmony_ci
528e41f4b71Sopenharmony_ciAs shown above, when the contacts list scrolls from group A to B, the alphabetical index bar on the right also changes from A to B. This scenario can be implemented by listening for the **onScrollIndex** event of the **List** component. The alphabet index bar is implemented using the [AlphabetIndexer](../reference/apis-arkui/arkui-ts/ts-container-alphabet-indexer.md) component.
529e41f4b71Sopenharmony_ci
530e41f4b71Sopenharmony_ciWhen the list scrolls, the **selectedIndex** value of the letter to highlight in the alphabet index bar is recalculated based on the **firstIndex** value of the item to which the list has scrolled. In the **AlphabetIndexer** component, the index of the highlighted item is set through the **selected** attribute. When the value of **selectedIndex** changes, the **AlphabetIndexer** component is re-rendered to highlight the corresponding letter.
531e41f4b71Sopenharmony_ci
532e41f4b71Sopenharmony_ci
533e41f4b71Sopenharmony_ci```ts
534e41f4b71Sopenharmony_ciconst alphabets = ['#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
535e41f4b71Sopenharmony_ci  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
536e41f4b71Sopenharmony_ci@Entry
537e41f4b71Sopenharmony_ci@Component
538e41f4b71Sopenharmony_cistruct ContactsList {
539e41f4b71Sopenharmony_ci  @State selectedIndex: number = 0;
540e41f4b71Sopenharmony_ci  private listScroller: Scroller = new Scroller();
541e41f4b71Sopenharmony_ci
542e41f4b71Sopenharmony_ci  build() {
543e41f4b71Sopenharmony_ci    Stack({ alignContent: Alignment.End }) {
544e41f4b71Sopenharmony_ci      List({ scroller: this.listScroller }) {}
545e41f4b71Sopenharmony_ci      .onScrollIndex((firstIndex: number) => {
546e41f4b71Sopenharmony_ci        // Recalculate the value of this.selectedIndex in the alphabetical index bar based on the index of the item to which the list has scrolled.
547e41f4b71Sopenharmony_ci      })
548e41f4b71Sopenharmony_ci
549e41f4b71Sopenharmony_ci      // <AlphabetIndexer> component
550e41f4b71Sopenharmony_ci      AlphabetIndexer({ arrayValue: alphabets, selected: 0 })
551e41f4b71Sopenharmony_ci        .selected(this.selectedIndex)
552e41f4b71Sopenharmony_ci    }
553e41f4b71Sopenharmony_ci  }
554e41f4b71Sopenharmony_ci}
555e41f4b71Sopenharmony_ci```
556e41f4b71Sopenharmony_ci
557e41f4b71Sopenharmony_ci>**NOTE**
558e41f4b71Sopenharmony_ci>
559e41f4b71Sopenharmony_ci>During index calculation, each **ListItemGroup** component is taken as a whole and assigned an index, and the indexes of the list items within are not included in the calculation.
560e41f4b71Sopenharmony_ci
561e41f4b71Sopenharmony_ci
562e41f4b71Sopenharmony_ci## Responding to Swipe on List Items
563e41f4b71Sopenharmony_ci
564e41f4b71Sopenharmony_ciSwipe menus are common in many applications. For example, a messaging application generally provides a swipe-to-delete feature for its message list. This feature allows users to delete a message by swiping left on it and touching the delete button, as shown in the following figure. For details about how to add a badge to the profile picture of a list item, see [Adding a Badge to a List Item](#adding-a-badge-to-a-list-item).
565e41f4b71Sopenharmony_ci
566e41f4b71Sopenharmony_ci**Figure 15** Swipe-to-delete feature 
567e41f4b71Sopenharmony_ci
568e41f4b71Sopenharmony_ci![en-us_image_0000001563060773](figures/en-us_image_0000001563060773.gif)
569e41f4b71Sopenharmony_ci
570e41f4b71Sopenharmony_ciSwiping left or right on a list item can be implemented through the [swipeAction](../reference/apis-arkui/arkui-ts/ts-container-listitem.md#attributes) attribute. In initialization of the **swipeAction** attribute, the **SwipeActionOptions** parameter is mandatory, wherein the **start** parameter indicates the component that appears from the start edge when the list item is swiped right, and the **end** parameter indicates the component that appears from the end edge when the list item is swiped left.
571e41f4b71Sopenharmony_ci
572e41f4b71Sopenharmony_ciIn the example of the message list, the **end** parameter is set to a custom delete button. In initialization of the **end** attribute, the index of the sliding list item is passed to the delete button. When the user touches the delete button, the data corresponding to the list item is deleted based on the index.
573e41f4b71Sopenharmony_ci
574e41f4b71Sopenharmony_ci1. Build the component that appears from the end edge when the list item is swiped left.
575e41f4b71Sopenharmony_ci
576e41f4b71Sopenharmony_ci    ```ts
577e41f4b71Sopenharmony_ci    @Builder itemEnd(index: number) {
578e41f4b71Sopenharmony_ci      // Build the component that appears from the end edge when the list item is swiped left.
579e41f4b71Sopenharmony_ci      Button({ type: ButtonType.Circle }) {
580e41f4b71Sopenharmony_ci        Image($r('app.media.ic_public_delete_filled'))
581e41f4b71Sopenharmony_ci          .width(20)
582e41f4b71Sopenharmony_ci          .height(20)
583e41f4b71Sopenharmony_ci      }
584e41f4b71Sopenharmony_ci      .onClick(() => {
585e41f4b71Sopenharmony_ci        // this.messages is the list data source, which can be constructed as required. A specified data item can be deleted from the data source upon click.
586e41f4b71Sopenharmony_ci        this.messages.splice(index, 1);
587e41f4b71Sopenharmony_ci      })
588e41f4b71Sopenharmony_ci    }
589e41f4b71Sopenharmony_ci    ```
590e41f4b71Sopenharmony_ci
591e41f4b71Sopenharmony_ci2. Binds the **swipeAction** attribute to a list item that can be swiped left.
592e41f4b71Sopenharmony_ci
593e41f4b71Sopenharmony_ci    ```ts
594e41f4b71Sopenharmony_ci    // When constructing a list, use ForEach to render list items based on the data source this.messages.
595e41f4b71Sopenharmony_ci    ListItem() {
596e41f4b71Sopenharmony_ci      // ...
597e41f4b71Sopenharmony_ci    }
598e41f4b71Sopenharmony_ci    .swipeAction({
599e41f4b71Sopenharmony_ci      end: {
600e41f4b71Sopenharmony_ci        // index is the index of the list item.
601e41f4b71Sopenharmony_ci        builder: () => { this.itemEnd(index) },
602e41f4b71Sopenharmony_ci      }
603e41f4b71Sopenharmony_ci    }) // Set the swipe action.
604e41f4b71Sopenharmony_ci    ```
605e41f4b71Sopenharmony_ci
606e41f4b71Sopenharmony_ci## Adding a Badge to a List Item
607e41f4b71Sopenharmony_ci
608e41f4b71Sopenharmony_ciA badge is an intuitive, unobtrusive visual indicator to draw attention and convey a specific message. For example, a badge can be displayed in the upper right corner of the contact's profile picture to indicate that there is a new message from that contact, as shown in the following figure.
609e41f4b71Sopenharmony_ci
610e41f4b71Sopenharmony_ci  **Figure 16** Adding a badge to a list item 
611e41f4b71Sopenharmony_ci
612e41f4b71Sopenharmony_ci![en-us_image_0000001511580952](figures/en-us_image_0000001511580952.png)
613e41f4b71Sopenharmony_ci
614e41f4b71Sopenharmony_ciTo add a badge, use the [Badge](../reference/apis-arkui/arkui-ts/ts-container-badge.md) component in **ListItem**. The **Badge** component is a container that can be attached to another component for tagging.
615e41f4b71Sopenharmony_ci
616e41f4b71Sopenharmony_ciIn this example, when implementing the **Image** component for presenting the profile picture of a list item, add it to **Badge** as a child component.
617e41f4b71Sopenharmony_ci
618e41f4b71Sopenharmony_ciIn the **Badge** component, the **count** and **position** parameters are used to set the number of notifications and the position to display the badge, respectively. You can also use the **style** parameter to spruce up the badge.
619e41f4b71Sopenharmony_ci
620e41f4b71Sopenharmony_ci
621e41f4b71Sopenharmony_ci```ts
622e41f4b71Sopenharmony_ciListItem() {
623e41f4b71Sopenharmony_ci  Badge({
624e41f4b71Sopenharmony_ci    count: 1,
625e41f4b71Sopenharmony_ci    position: BadgePosition.RightTop,
626e41f4b71Sopenharmony_ci    style: { badgeSize: 16, badgeColor: '#FA2A2D' }
627e41f4b71Sopenharmony_ci  }) {
628e41f4b71Sopenharmony_ci    // The <Image> component implements the contact profile picture.
629e41f4b71Sopenharmony_ci    // ...
630e41f4b71Sopenharmony_ci  }
631e41f4b71Sopenharmony_ci}
632e41f4b71Sopenharmony_ci```
633e41f4b71Sopenharmony_ci
634e41f4b71Sopenharmony_ci
635e41f4b71Sopenharmony_ci## Implementing Pull-Down-to-Refresh and Pull-Up-to-Load
636e41f4b71Sopenharmony_ci
637e41f4b71Sopenharmony_ciThe pull-down-to-refresh and pull-up-to-load features are widely used in mobile applications, such as news applications. In effect, the implementation of these two features follows the same process: (1) As response to a [touch event](../reference/apis-arkui/arkui-ts/ts-universal-events-touch.md), a refresh or load view is displayed at the top or bottom of the page; (2) when the refresh or load is complete, the refresh or load view is hidden.
638e41f4b71Sopenharmony_ci
639e41f4b71Sopenharmony_ciThe following describes the implementation of the pull-and-refresh feature:
640e41f4b71Sopenharmony_ci
641e41f4b71Sopenharmony_ci1. Listen for the finger press event and record the value of the initial position.
642e41f4b71Sopenharmony_ci
643e41f4b71Sopenharmony_ci2. Listen for the finger movement event, and record and calculate the difference between the value of the current position and the initial value. If the difference is greater than 0, the finger moves downward. Set the maximum value for the movement.
644e41f4b71Sopenharmony_ci
645e41f4b71Sopenharmony_ci3. Listen for the finger lift event. If the movement reaches the maximum value, trigger data loading and display the refresh view. After the loading is complete, hide the view.
646e41f4b71Sopenharmony_ci
647e41f4b71Sopenharmony_ci<!--RP1--><!--RP1End-->
648e41f4b71Sopenharmony_ci
649e41f4b71Sopenharmony_ci<!--Del-->
650e41f4b71Sopenharmony_ci  <!--DelEnd-->
651e41f4b71Sopenharmony_ci
652e41f4b71Sopenharmony_ci
653e41f4b71Sopenharmony_ci## Editing a List
654e41f4b71Sopenharmony_ci
655e41f4b71Sopenharmony_ciThe list editing mode is frequently used in various scenarios, such as to-do list management, file management, and note management. In editing mode, adding and deleting list items are the most basic functions. The core is to add and delete data in the data set corresponding to the list items.
656e41f4b71Sopenharmony_ci
657e41f4b71Sopenharmony_ciThe following uses to-do list management as an example to describe how to quickly add and delete list items.
658e41f4b71Sopenharmony_ci
659e41f4b71Sopenharmony_ci
660e41f4b71Sopenharmony_ci### Adding a List Item
661e41f4b71Sopenharmony_ci
662e41f4b71Sopenharmony_ciAs shown below, when a user touches **Add**, a page is displayed for the user to set options for the new list item. After the user touches **OK**, the corresponding item is added to the list.
663e41f4b71Sopenharmony_ci
664e41f4b71Sopenharmony_ci  **Figure 17** Adding a to-do task 
665e41f4b71Sopenharmony_ci
666e41f4b71Sopenharmony_ci![en-us_image_0000001511740556](figures/en-us_image_0000001511740556.gif)
667e41f4b71Sopenharmony_ci
668e41f4b71Sopenharmony_ciThe process of implementing the addition feature is as follows:
669e41f4b71Sopenharmony_ci
670e41f4b71Sopenharmony_ci1. Define the list item data structure. In this example, a to-do data structure is defined.
671e41f4b71Sopenharmony_ci
672e41f4b71Sopenharmony_ci   ```ts
673e41f4b71Sopenharmony_ci   //ToDo.ets
674e41f4b71Sopenharmony_ci   import { util } from '@kit.ArkTS'
675e41f4b71Sopenharmony_ci
676e41f4b71Sopenharmony_ci   export class ToDo {
677e41f4b71Sopenharmony_ci     key: string = util.generateRandomUUID(true);
678e41f4b71Sopenharmony_ci     name: string;
679e41f4b71Sopenharmony_ci
680e41f4b71Sopenharmony_ci     constructor(name: string) {
681e41f4b71Sopenharmony_ci       this.name = name;
682e41f4b71Sopenharmony_ci     }
683e41f4b71Sopenharmony_ci   }
684e41f4b71Sopenharmony_ci   ```
685e41f4b71Sopenharmony_ci
686e41f4b71Sopenharmony_ci2. Build the overall list layout and list items.
687e41f4b71Sopenharmony_ci
688e41f4b71Sopenharmony_ci   ```ts
689e41f4b71Sopenharmony_ci   //ToDoListItem.ets
690e41f4b71Sopenharmony_ci   import { ToDo } from './ToDo';
691e41f4b71Sopenharmony_ci   @Component
692e41f4b71Sopenharmony_ci   export struct ToDoListItem {
693e41f4b71Sopenharmony_ci     @Link isEditMode: boolean
694e41f4b71Sopenharmony_ci     @Link selectedItems: ToDo[]
695e41f4b71Sopenharmony_ci     private toDoItem: ToDo = new ToDo("");
696e41f4b71Sopenharmony_ci
697e41f4b71Sopenharmony_ci     build() {
698e41f4b71Sopenharmony_ci      Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
699e41f4b71Sopenharmony_ci        // ...
700e41f4b71Sopenharmony_ci      }
701e41f4b71Sopenharmony_ci      .width('100%')
702e41f4b71Sopenharmony_ci      .height(80)
703e41f4b71Sopenharmony_ci      // .padding(): Set this parameter based on the use case.
704e41f4b71Sopenharmony_ci      .borderRadius(24)
705e41f4b71Sopenharmony_ci      // .linearGradient(): Set this parameter based on the use case.
706e41f4b71Sopenharmony_ci      .gesture(
707e41f4b71Sopenharmony_ci        GestureGroup(GestureMode.Exclusive,
708e41f4b71Sopenharmony_ci        LongPressGesture()
709e41f4b71Sopenharmony_ci          .onAction(() => {
710e41f4b71Sopenharmony_ci            // ...
711e41f4b71Sopenharmony_ci          })
712e41f4b71Sopenharmony_ci        )
713e41f4b71Sopenharmony_ci      )
714e41f4b71Sopenharmony_ci     }
715e41f4b71Sopenharmony_ci   }
716e41f4b71Sopenharmony_ci   ```
717e41f4b71Sopenharmony_ci
718e41f4b71Sopenharmony_ci3. Initialize the to-do list data and available items, and build the list layout and list items.
719e41f4b71Sopenharmony_ci
720e41f4b71Sopenharmony_ci   ```ts
721e41f4b71Sopenharmony_ci   //ToDoList.ets
722e41f4b71Sopenharmony_ci   import { ToDo } from './ToDo';
723e41f4b71Sopenharmony_ci   import { ToDoListItem } from './ToDoListItem';
724e41f4b71Sopenharmony_ci   
725e41f4b71Sopenharmony_ci   @Entry
726e41f4b71Sopenharmony_ci   @Component
727e41f4b71Sopenharmony_ci   struct ToDoList {
728e41f4b71Sopenharmony_ci     @State toDoData: ToDo[] = []
729e41f4b71Sopenharmony_ci     @Watch('onEditModeChange') @State isEditMode: boolean = false
730e41f4b71Sopenharmony_ci     @State selectedItems: ToDo[] = []
731e41f4b71Sopenharmony_ci    private availableThings: string[] = ['Reading', 'Fitness', 'Travel','Music','Movie', 'Singing']
732e41f4b71Sopenharmony_ci   
733e41f4b71Sopenharmony_ci     onEditModeChange() {
734e41f4b71Sopenharmony_ci       if (!this.isEditMode) {
735e41f4b71Sopenharmony_ci         this.selectedItems = []
736e41f4b71Sopenharmony_ci       }
737e41f4b71Sopenharmony_ci    }
738e41f4b71Sopenharmony_ci   
739e41f4b71Sopenharmony_ci     build() {
740e41f4b71Sopenharmony_ci       Column() {
741e41f4b71Sopenharmony_ci         Row() {
742e41f4b71Sopenharmony_ci           if (this.isEditMode) {
743e41f4b71Sopenharmony_ci             Text('X')
744e41f4b71Sopenharmony_ci               .fontSize(20)
745e41f4b71Sopenharmony_ci               .onClick(() => {
746e41f4b71Sopenharmony_ci                 this.isEditMode = false;
747e41f4b71Sopenharmony_ci               })
748e41f4b71Sopenharmony_ci               .margin({ left: 20, right: 20 })
749e41f4b71Sopenharmony_ci           } else {
750e41f4b71Sopenharmony_ci             Text('To-Do')
751e41f4b71Sopenharmony_ci               .fontSize(36)
752e41f4b71Sopenharmony_ci               .margin({ left: 40 })
753e41f4b71Sopenharmony_ci             Blank()
754e41f4b71Sopenharmony_ci             Text('+') // Provide an entry for adding a list item, that is, add a click event for the add button.
755e41f4b71Sopenharmony_ci               .onClick(() => {
756e41f4b71Sopenharmony_ci                 this.getUIContext().showTextPickerDialog({
757e41f4b71Sopenharmony_ci                   range: this.availableThings,
758e41f4b71Sopenharmony_ci                   onAccept: (value: TextPickerResult) => {
759e41f4b71Sopenharmony_ci                     let arr = Array.isArray(value.index) ? value.index : [value.index];
760e41f4b71Sopenharmony_ci                     for (let i = 0; i < arr.length; i++) {
761e41f4b71Sopenharmony_ci                       this.toDoData.push(new ToDo(this.availableThings[arr[i]])); // Add to-do list items (available items).
762e41f4b71Sopenharmony_ci                     }
763e41f4b71Sopenharmony_ci                   },
764e41f4b71Sopenharmony_ci                 })
765e41f4b71Sopenharmony_ci               })
766e41f4b71Sopenharmony_ci           }
767e41f4b71Sopenharmony_ci           List({ space: 10 }) {
768e41f4b71Sopenharmony_ci             ForEach(this.toDoData, (toDoItem: ToDo) => {
769e41f4b71Sopenharmony_ci               ListItem() {
770e41f4b71Sopenharmony_ci                 // Place each item of toDoData into the list item in the form of model.
771e41f4b71Sopenharmony_ci                 ToDoListItem({
772e41f4b71Sopenharmony_ci                   isEditMode: this.isEditMode,
773e41f4b71Sopenharmony_ci                   toDoItem: toDoItem,
774e41f4b71Sopenharmony_ci                   selectedItems: this.selectedItems })
775e41f4b71Sopenharmony_ci               }
776e41f4b71Sopenharmony_ci             }, (toDoItem: ToDo) => toDoItem.key.toString())
777e41f4b71Sopenharmony_ci           }
778e41f4b71Sopenharmony_ci         }
779e41f4b71Sopenharmony_ci       }
780e41f4b71Sopenharmony_ci     }
781e41f4b71Sopenharmony_ci   }
782e41f4b71Sopenharmony_ci   ```
783e41f4b71Sopenharmony_ci
784e41f4b71Sopenharmony_ci
785e41f4b71Sopenharmony_ci### Deleting a List Item
786e41f4b71Sopenharmony_ci
787e41f4b71Sopenharmony_ciAs shown below, when the user long presses a list item to enter the deletion mode, a page is displayed for the user to delete the list item. After the user selects the list item and touches the delete button, the list item is deleted.
788e41f4b71Sopenharmony_ci
789e41f4b71Sopenharmony_ci  **Figure 18** Deleting a to-do task 
790e41f4b71Sopenharmony_ci
791e41f4b71Sopenharmony_ci![en-us_image_0000001562820877](figures/en-us_image_0000001562820877.gif)
792e41f4b71Sopenharmony_ci
793e41f4b71Sopenharmony_ciThe process of implementing the deletion feature is as follows:
794e41f4b71Sopenharmony_ci
795e41f4b71Sopenharmony_ci1. Generally, the deletion feature is available only after the list enters the editing mode. Therefore, the entry to the editing mode needs to be provided.
796e41f4b71Sopenharmony_ci   In this example, by listening for the long press event of a list item, the list enters the editing mode when the user long presses a list item.
797e41f4b71Sopenharmony_ci
798e41f4b71Sopenharmony_ci    ```ts
799e41f4b71Sopenharmony_ci    // Structure reference
800e41f4b71Sopenharmony_ci    export class ToDo {
801e41f4b71Sopenharmony_ci      key: string = util.generateRandomUUID(true);
802e41f4b71Sopenharmony_ci      name: string;
803e41f4b71Sopenharmony_ci      toDoData: ToDo[] = [];
804e41f4b71Sopenharmony_ci
805e41f4b71Sopenharmony_ci      constructor(name: string) {
806e41f4b71Sopenharmony_ci        this.name = name;
807e41f4b71Sopenharmony_ci      }
808e41f4b71Sopenharmony_ci    }
809e41f4b71Sopenharmony_ci    ```
810e41f4b71Sopenharmony_ci    ```ts
811e41f4b71Sopenharmony_ci    // Implementation reference
812e41f4b71Sopenharmony_ci    Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
813e41f4b71Sopenharmony_ci      // ...
814e41f4b71Sopenharmony_ci    }
815e41f4b71Sopenharmony_ci    .gesture(
816e41f4b71Sopenharmony_ci    GestureGroup(GestureMode.Exclusive,
817e41f4b71Sopenharmony_ci      LongPressGesture()
818e41f4b71Sopenharmony_ci        .onAction(() => {
819e41f4b71Sopenharmony_ci          if (!this.isEditMode) {
820e41f4b71Sopenharmony_ci            this.isEditMode = true; // Enter the editing mode.
821e41f4b71Sopenharmony_ci          }
822e41f4b71Sopenharmony_ci        })
823e41f4b71Sopenharmony_ci      )
824e41f4b71Sopenharmony_ci    )
825e41f4b71Sopenharmony_ci    ```
826e41f4b71Sopenharmony_ci   
827e41f4b71Sopenharmony_ci2. Respond to the user's selection and record the list items to be deleted.
828e41f4b71Sopenharmony_ci   In this to-do list example, the list items are selected or unselected according to the user's selection.
829e41f4b71Sopenharmony_ci
830e41f4b71Sopenharmony_ci    ```ts
831e41f4b71Sopenharmony_ci   // Structure reference
832e41f4b71Sopenharmony_ci   import { util } from '@kit.ArkTS'
833e41f4b71Sopenharmony_ci   export class ToDo {
834e41f4b71Sopenharmony_ci     key: string = util.generateRandomUUID(true);
835e41f4b71Sopenharmony_ci     name: string;
836e41f4b71Sopenharmony_ci     toDoData: ToDo[] = [];
837e41f4b71Sopenharmony_ci
838e41f4b71Sopenharmony_ci     constructor(name: string) {
839e41f4b71Sopenharmony_ci       this.name = name;
840e41f4b71Sopenharmony_ci     }
841e41f4b71Sopenharmony_ci   }
842e41f4b71Sopenharmony_ci    ```
843e41f4b71Sopenharmony_ci    ```ts
844e41f4b71Sopenharmony_ci    // Implementation reference
845e41f4b71Sopenharmony_ci    if (this.isEditMode) {
846e41f4b71Sopenharmony_ci      Checkbox()
847e41f4b71Sopenharmony_ci        .onChange((isSelected) => {
848e41f4b71Sopenharmony_ci          if (isSelected) {
849e41f4b71Sopenharmony_ci            When this.selectedItems.push(toDoList.toDoItem) // this.selectedItems is selected, the selected list items are recorded. You can construct the list items based on the site requirements.
850e41f4b71Sopenharmony_ci          } else {
851e41f4b71Sopenharmony_ci            let index = this.selectedItems.indexOf(toDoList.toDoItem)
852e41f4b71Sopenharmony_ci            if (index !== -1) {
853e41f4b71Sopenharmony_ci              this.selectedItems.splice(index, 1) // When an item is deselected, it is deleted from the selectedItems array.
854e41f4b71Sopenharmony_ci            }
855e41f4b71Sopenharmony_ci          }
856e41f4b71Sopenharmony_ci        })
857e41f4b71Sopenharmony_ci    }
858e41f4b71Sopenharmony_ci    ```
859e41f4b71Sopenharmony_ci   
860e41f4b71Sopenharmony_ci3. Respond to the user's clicking the delete button and delete the corresponding items from the list.
861e41f4b71Sopenharmony_ci
862e41f4b71Sopenharmony_ci    ```ts
863e41f4b71Sopenharmony_ci    // Structure reference
864e41f4b71Sopenharmony_ci    import { util } from '@kit.ArkTS'
865e41f4b71Sopenharmony_ci    export class ToDo {
866e41f4b71Sopenharmony_ci      key: string = util.generateRandomUUID(true);
867e41f4b71Sopenharmony_ci      name: string;
868e41f4b71Sopenharmony_ci      toDoData: ToDo[] = [];
869e41f4b71Sopenharmony_ci
870e41f4b71Sopenharmony_ci      constructor(name: string) {
871e41f4b71Sopenharmony_ci        this.name = name;
872e41f4b71Sopenharmony_ci      }
873e41f4b71Sopenharmony_ci    }
874e41f4b71Sopenharmony_ci    ```
875e41f4b71Sopenharmony_ci    ```ts
876e41f4b71Sopenharmony_ci    // Implementation reference
877e41f4b71Sopenharmony_ci    Button ('Delete')
878e41f4b71Sopenharmony_ci      .onClick(() => {
879e41f4b71Sopenharmony_ci        // this.toDoData is the to-do list item, which can be constructed based on service requirements. After an item is clicked, the corresponding data is removed.
880e41f4b71Sopenharmony_ci        let leftData = this.toDoData.filter((item) => {
881e41f4b71Sopenharmony_ci          return !this.selectedItems.find((selectedItem) => selectedItem == item);
882e41f4b71Sopenharmony_ci        })
883e41f4b71Sopenharmony_ci        this.toDoData = leftData;
884e41f4b71Sopenharmony_ci        this.isEditMode = false;
885e41f4b71Sopenharmony_ci      })
886e41f4b71Sopenharmony_ci    ```
887e41f4b71Sopenharmony_ci
888e41f4b71Sopenharmony_ci
889e41f4b71Sopenharmony_ci## Handling a Long List
890e41f4b71Sopenharmony_ci
891e41f4b71Sopenharmony_ci[ForEach](../quick-start/arkts-rendering-control-foreach.md) is applicable to short lists. With regard to a long list with a large number of list items, using **ForEach** will greatly slow down page loading, as it loads all list items at once. Therefore, for better list performance, use [LazyForEach](../quick-start/arkts-rendering-control-lazyforeach.md) instead to implement on-demand iterative data loading.
892e41f4b71Sopenharmony_ci
893e41f4b71Sopenharmony_ciFor details about the implementation, see the example in [LazyForEach: Lazy Data Loading](../quick-start/arkts-rendering-control-lazyforeach.md).
894e41f4b71Sopenharmony_ci
895e41f4b71Sopenharmony_ciWhen the list is rendered in lazy loading mode, to improve the list scrolling experience and minimize white blocks during list scrolling, you can use the **cachedCount** parameter of the **List** component. This parameter sets the number of list items preloaded outside of the screen and is valid only in **LazyForEach**.
896e41f4b71Sopenharmony_ci
897e41f4b71Sopenharmony_ci
898e41f4b71Sopenharmony_ci```ts
899e41f4b71Sopenharmony_ciList() {
900e41f4b71Sopenharmony_ci  // ...
901e41f4b71Sopenharmony_ci}.cachedCount(3)
902e41f4b71Sopenharmony_ci```
903e41f4b71Sopenharmony_ci
904e41f4b71Sopenharmony_ciThe following uses a vertical list as an example:
905e41f4b71Sopenharmony_ci
906e41f4b71Sopenharmony_ci- If lazy loading is used for list items and the list contains only one column, the number of the list items to cache before and after the currently displayed one equals the value of **cachedCount**. If the list contains multiple columns, the number of the list items to cache is the value of **cachedCount** multiplied by the number of columns.
907e41f4b71Sopenharmony_ci
908e41f4b71Sopenharmony_ci- If lazy loading is used for list item groups, the number of the list item groups to cache before and after the currently displayed one equals the value of **cachedCount**, regardless of the number of columns.
909e41f4b71Sopenharmony_ci
910e41f4b71Sopenharmony_ci>**NOTE**
911e41f4b71Sopenharmony_ci>
912e41f4b71Sopenharmony_ci>1. A greater **cachedCount** value may result in higher CPU and memory overhead of the UI. Adjust the value by taking into account both the comprehensive performance and user experience.
913e41f4b71Sopenharmony_ci>
914e41f4b71Sopenharmony_ci>2. When a list uses data lazy loading, all list items except the list items in the display area and the cached list items are destroyed.
915e41f4b71Sopenharmony_ci
916e41f4b71Sopenharmony_ci
917e41f4b71Sopenharmony_ci## Collapsing and Expanding
918e41f4b71Sopenharmony_ci
919e41f4b71Sopenharmony_ciThe collapsing and expanding of list items are widely used, often applied in scenarios such as displaying information lists and filling out forms.
920e41f4b71Sopenharmony_ci
921e41f4b71Sopenharmony_ci  **Figure 19** Collapsing and expanding of list items
922e41f4b71Sopenharmony_ci
923e41f4b71Sopenharmony_ci![zh-cn_image_0000001949866104](figures/zh-cn_image_0000001949866104.gif)
924e41f4b71Sopenharmony_ci
925e41f4b71Sopenharmony_ciThe process of implementing the collapsing and expanding effect of list items is as follows:
926e41f4b71Sopenharmony_ci
927e41f4b71Sopenharmony_ci1. Define the list item data structure.
928e41f4b71Sopenharmony_ci
929e41f4b71Sopenharmony_ci    ```ts
930e41f4b71Sopenharmony_ci    interface ItemInfo {
931e41f4b71Sopenharmony_ci      index: number,
932e41f4b71Sopenharmony_ci      name: string,
933e41f4b71Sopenharmony_ci      label: ResourceStr,
934e41f4b71Sopenharmony_ci      type?: string,
935e41f4b71Sopenharmony_ci    }
936e41f4b71Sopenharmony_ci
937e41f4b71Sopenharmony_ci    interface ItemGroupInfo extends ItemInfo {
938e41f4b71Sopenharmony_ci      children: ItemInfo[]
939e41f4b71Sopenharmony_ci    }
940e41f4b71Sopenharmony_ci    ```
941e41f4b71Sopenharmony_ci
942e41f4b71Sopenharmony_ci2. Construct a list structure.
943e41f4b71Sopenharmony_ci
944e41f4b71Sopenharmony_ci    ```ts
945e41f4b71Sopenharmony_ci    build() {
946e41f4b71Sopenharmony_ci      Column() {
947e41f4b71Sopenharmony_ci        // ...
948e41f4b71Sopenharmony_ci
949e41f4b71Sopenharmony_ci        List({ space: 10 }) {
950e41f4b71Sopenharmony_ci          ForEach(this.routes, (itemGroup: ItemGroupInfo) => {
951e41f4b71Sopenharmony_ci            ListItemGroup({
952e41f4b71Sopenharmony_ci              header: this.ListItemGroupHeader(itemGroup),
953e41f4b71Sopenharmony_ci              style: ListItemGroupStyle.CARD,
954e41f4b71Sopenharmony_ci            }) {
955e41f4b71Sopenharmony_ci              if (this.expandedItems[itemGroup.index] && itemGroup.children) {
956e41f4b71Sopenharmony_ci                ForEach(itemGroup.children, (item: ItemInfo) => {
957e41f4b71Sopenharmony_ci                  ListItem({ style: ListItemStyle.CARD }) {
958e41f4b71Sopenharmony_ci                    Row() {
959e41f4b71Sopenharmony_ci                      Text(item.name)
960e41f4b71Sopenharmony_ci                      Blank()
961e41f4b71Sopenharmony_ci                      if (item.type === 'Image') {
962e41f4b71Sopenharmony_ci                        Image(item.label)
963e41f4b71Sopenharmony_ci                          .height(20)
964e41f4b71Sopenharmony_ci                          .width(20)
965e41f4b71Sopenharmony_ci                      } else {
966e41f4b71Sopenharmony_ci                        Text(item.label)
967e41f4b71Sopenharmony_ci                      }
968e41f4b71Sopenharmony_ci                      Image($r('sys.media.ohos_ic_public_arrow_right'))
969e41f4b71Sopenharmony_ci                        .fillColor($r('sys.color.ohos_id_color_fourth'))
970e41f4b71Sopenharmony_ci                        .height(30)
971e41f4b71Sopenharmony_ci                        .width(30)
972e41f4b71Sopenharmony_ci                    }
973e41f4b71Sopenharmony_ci                    .width("100%")
974e41f4b71Sopenharmony_ci                  }
975e41f4b71Sopenharmony_ci                  .width("100%")
976e41f4b71Sopenharmony_ci                  .animation({ curve: curves.interpolatingSpring(0, 1, 528, 39) })
977e41f4b71Sopenharmony_ci                })
978e41f4b71Sopenharmony_ci              }
979e41f4b71Sopenharmony_ci            }.clip(true)
980e41f4b71Sopenharmony_ci          })
981e41f4b71Sopenharmony_ci        }
982e41f4b71Sopenharmony_ci        .width("100%")
983e41f4b71Sopenharmony_ci      }
984e41f4b71Sopenharmony_ci      .width('100%')
985e41f4b71Sopenharmony_ci      .height('100%')
986e41f4b71Sopenharmony_ci      .justifyContent(FlexAlign.Start)
987e41f4b71Sopenharmony_ci      .backgroundColor($r('sys.color.ohos_id_color_sub_background'))
988e41f4b71Sopenharmony_ci    }
989e41f4b71Sopenharmony_ci    ```
990e41f4b71Sopenharmony_ci
991e41f4b71Sopenharmony_ci3. Control whether each list item is expanded by changing the state of **ListItem**, and achieve the animation effects during the expanding and collapsing process through **animation** and **animateTo**.
992e41f4b71Sopenharmony_ci
993e41f4b71Sopenharmony_ci    ```ts
994e41f4b71Sopenharmony_ci    @Builder
995e41f4b71Sopenharmony_ci    ListItemGroupHeader(itemGroup: ItemGroupInfo) {
996e41f4b71Sopenharmony_ci      Row() {
997e41f4b71Sopenharmony_ci        Text(itemGroup.label)
998e41f4b71Sopenharmony_ci        Blank()
999e41f4b71Sopenharmony_ci        Image($r('sys.media.ohos_ic_public_arrow_down'))
1000e41f4b71Sopenharmony_ci          .fillColor($r('sys.color.ohos_id_color_fourth'))
1001e41f4b71Sopenharmony_ci          .height(30)
1002e41f4b71Sopenharmony_ci          .width(30)
1003e41f4b71Sopenharmony_ci          .rotate({ angle: !!itemGroup.children.length ? (this.expandedItems[itemGroup.index] ? 180 : 0) : 180 })
1004e41f4b71Sopenharmony_ci          .animation({ curve: curves.interpolatingSpring(0, 1, 228, 22) })
1005e41f4b71Sopenharmony_ci      }
1006e41f4b71Sopenharmony_ci      .width("100%")
1007e41f4b71Sopenharmony_ci      .padding(10)
1008e41f4b71Sopenharmony_ci      .animation({ curve: curves.interpolatingSpring(0, 1, 528, 39) })
1009e41f4b71Sopenharmony_ci      .onTouch((event) => {
1010e41f4b71Sopenharmony_ci        if (event.type === TouchType.Up) {
1011e41f4b71Sopenharmony_ci          if (itemGroup.children.length) {
1012e41f4b71Sopenharmony_ci            animateTo({ curve: curves.interpolatingSpring(0, 1, 528, 39) }, () => {
1013e41f4b71Sopenharmony_ci              this.expandedItems[itemGroup.index] = !this.expandedItems[itemGroup.index]
1014e41f4b71Sopenharmony_ci            })
1015e41f4b71Sopenharmony_ci          }
1016e41f4b71Sopenharmony_ci        }
1017e41f4b71Sopenharmony_ci      })
1018e41f4b71Sopenharmony_ci    }
1019e41f4b71Sopenharmony_ci    ```
1020e41f4b71Sopenharmony_ci
1021