1# WaterFlow
2
3
4The **WaterFlow** component is a water flow container that consists of cells formed by rows and columns and arranges items of different sizes from top to bottom according to the preset rules.
5
6
7> **NOTE**
8>
9> This component is supported since API version 9. Updates will be marked with a superscript to indicate their earliest API version.
10
11
12## Child Components
13
14
15Only the [FlowItem](ts-container-flowitem.md) child component is allowed, with support for [if/else](../../../quick-start/arkts-rendering-control-ifelse.md), [ForEach](../../../quick-start/arkts-rendering-control-foreach.md), [LazyForEach](../../../quick-start/arkts-rendering-control-lazyforeach.md), and [Repeat](../../../quick-start/arkts-new-rendering-control-repeat.md) rendering control.
16
17>  **NOTE**
18>
19>  When its **visibility** attribute is set to **None**, a **FlowItem** is not displayed in the container, but its **columnsGap**, **rowsGap**, and **margin** settings are still effective.
20
21## APIs
22
23WaterFlow(options?:  WaterFlowOptions)
24
25**Atomic service API**: This API can be used in atomic services since API version 11.
26
27**System capability**: SystemCapability.ArkUI.ArkUI.Full
28
29**Parameters**
30
31| Name| Type| Mandatory| Description|
32| -------- | -------- | -------- | -------- |
33| options |  [WaterFlowOptions](#waterflowoptions)| No| Parameters of the **WaterFlow** component.|
34
35
36## WaterFlowOptions
37
38**System capability**: SystemCapability.ArkUI.ArkUI.Full
39
40| Name    | Type                                       | Mandatory| Description                                    |
41| ---------- | ----------------------------------------------- | ------ | -------------------------------------------- |
42| footer |  [CustomBuilder](ts-types.md#custombuilder8) | No  | Footer of the **WaterFlow** component.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
43| scroller | [Scroller](ts-container-scroll.md#scroller) | No  | Controller of the scrollable component, bound to the scrollable component.<br>**NOTE**<br>The same scroller cannot be bound to other scrollable components, such as [List](ts-container-list.md), [Grid](ts-container-grid.md), or [Scroll](ts-container-scroll.md).<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
44| sections<sup>12+</sup> |  [WaterFlowSections](#waterflowsections12) | No  | Water flow item sections. Different sections can have different numbers of columns.<br>**NOTE**<br>1. When **sections** is used, the **columnsTemplate** and **rowsTemplate** attributes are ignored.<br>2. When **sections** is used, the footer cannot be set separately. The last section can function as the footer.<br>**Atomic service API**: This API can be used in atomic services since API version 12. |
45| layoutMode<sup>12+</sup> |[WaterFlowLayoutMode](#waterflowlayoutmode12)| No| Layout mode of the **WaterFlow** component.<br>**NOTE**<br>Default value: [ALWAYS_TOP_DOWN](#waterflowlayoutmode12)<br>**Atomic service API**: This API can be used in atomic services since API version 12.
46
47
48## WaterFlowSections<sup>12+</sup>
49
50Describes the water flow item sections.
51
52> **NOTE**
53>
54> After the section information is modified using **splice**, **push**, and **update**, ensure that the total number of child nodes in all sections matches the actual total number of child nodes in the **WaterFlow** component. Any failure to do so may result in layout issues that prevent the **WaterFlow** component from scrolling properly.
55
56### constructor
57
58constructor()
59
60A constructor used to create a **WaterFlowSections** object.
61
62**Atomic service API**: This API can be used in atomic services since API version 12.
63
64**System capability**: SystemCapability.ArkUI.ArkUI.Full
65
66### splice<sup>12+</sup>
67
68splice(start: number, deleteCount?: number, sections?: Array\<SectionOptions\>): boolean
69
70Changes sections by removing or replacing an existing section and/or adding a section.
71
72**Atomic service API**: This API can be used in atomic services since API version 12.
73
74**System capability**: SystemCapability.ArkUI.ArkUI.Full
75
76**Parameters**
77
78| Name  | Type                           | Mandatory  | Description                  |
79| ---- | ----------------------------- | ---- | -------------------- |
80| start | number | Yes   | Zero-based index at which the changing starts. The value is converted to an integer.<br>**NOTE**<br>1. A negative index counts back from the end of the section list. If -**WaterFlowSections.length()** <= **start** < **0**, **start** + **array.length** is used.<br>2. If **start** < -**WaterFlowSections.length()**, **0** is used.<br>3. If **start** >= **WaterFlowSections.length()**, a new section is added at the end.|
81| deleteCount | number | No   | Number of sections to be deleted from the position specified by **start**.<br>**NOTE**<br>1. If **deleteCount** is omitted, or if its value is greater than or equal to the number of sections from the position specified by **start** to the end of the **WaterFlowSections**, then all sections from the position specified by **start** to the end of the **WaterFlowSections** will be deleted.<br>2. If **deleteCount** is **0** or a negative number, no sections are deleted.|
82| sections | Array<[SectionOptions](#sectionoptions12)> | No   | Sections to add to the section list, beginning from the position specified by **start**. If no section is specified, **splice()** will only delete sections from the **WaterFlow** component.|
83
84**Return value**
85
86| Type                                                        | Description                                                        |
87| ------------------------------------------------------------ | ------------------------------------------------------------ |
88| boolean | Whether the changing is successful. If the value of **itemsCount** in any section to add is not a positive integer, **false** is returned.|
89
90
91### push<sup>12+</sup>
92
93push(section: SectionOptions): boolean
94
95Adds the specified sections to the end of the **WaterFlow** component.
96
97**Atomic service API**: This API can be used in atomic services since API version 12.
98
99**System capability**: SystemCapability.ArkUI.ArkUI.Full
100
101**Parameters**
102
103| Name  | Type                           | Mandatory  | Description                  |
104| ---- | ----------------------------- | ---- | -------------------- |
105| section | [SectionOptions](#sectionoptions12) | Yes   | Sections to add to the end of the **WaterFlow** component.|
106
107**Return value**
108
109| Type                                                        | Description                                                        |
110| ------------------------------------------------------------ | ------------------------------------------------------------ |
111| boolean | Whether the adding is successful. If the value of **itemsCount** in any section to add is not a positive integer, **false** is returned.|
112
113### update<sup>12+</sup>
114
115update(sectionIndex: number, section: SectionOptions): boolean
116
117Updates the configuration of a specified water flow item section.
118
119**Atomic service API**: This API can be used in atomic services since API version 12.
120
121**System capability**: SystemCapability.ArkUI.ArkUI.Full
122
123**Parameters**
124
125| Name  | Type                           | Mandatory  | Description                  |
126| ---- | ----------------------------- | ---- | -------------------- |
127| sectionIndex | number | Yes   | Zero-based index of the water flow item section to update. The value is converted to an integer.<br>**NOTE**<br>1. A negative index counts back from the end of the section list. If -**WaterFlowSections.length()** <= **sectionIndex** < **0**, **sectionIndex** + **array.length** is used.<br>2. If **sectionIndex** < -**WaterFlowSections.length()**, **0** is used.<br>3. If **sectionIndex** >= **WaterFlowSections.length()**, a new section is added at the end.|
128| section | [SectionOptions](#sectionoptions12) | Yes   | New section configuration.|
129
130**Return value**
131
132| Type                                                        | Description                                                        |
133| ------------------------------------------------------------ | ------------------------------------------------------------ |
134| boolean | Whether the update is successful. If the value of **itemsCount** in any section to add is not a positive integer, **false** is returned.|
135
136### values<sup>12+</sup>
137
138values(): Array\<SectionOptions\>
139
140Obtains the configuration of all sections in the **WaterFlow** component.
141
142**Atomic service API**: This API can be used in atomic services since API version 12.
143
144**System capability**: SystemCapability.ArkUI.ArkUI.Full
145
146**Return value**
147
148| Type                                                        | Description                                                        |
149| ------------------------------------------------------------ | ------------------------------------------------------------ |
150| Array<[SectionOptions](#sectionoptions12)> | Configuration of all sections in the **WaterFlow** component.|
151
152### length<sup>12+</sup>
153
154length(): number
155
156Obtains the number of sections in the **WaterFlow** component.
157
158**Atomic service API**: This API can be used in atomic services since API version 12.
159
160**System capability**: SystemCapability.ArkUI.ArkUI.Full
161
162**Return value**
163
164| Type                                                        | Description                                                        |
165| ------------------------------------------------------------ | ------------------------------------------------------------ |
166| number | Number of sections in the **WaterFlow** component.|
167
168## SectionOptions<sup>12+</sup>
169
170Describes the configuration of the water flow item section.
171
172**Atomic service API**: This API can be used in atomic services since API version 12.
173
174**System capability**: SystemCapability.ArkUI.ArkUI.Full
175
176| Name| Type| Mandatory| Description|
177|------|-----|-----|-----|
178| itemsCount | number | Yes| Number of water flow items in the section. The value must be a positive integer. If the **splice**, **push**, or **update** APIs receive a section where the **itemsCount** value is less than 0, these APIs will not be executed.|
179| crossCount | number | No| Number of columns (in vertical layout) or rows (in horizontal layout).<br>Default value: **1**<br> If the value is less than 1, the default value is used.|
180| columnsGap | [Dimension](ts-types.md#dimension10) | No| Gap between columns. If this parameter is not set, the value of **columnsGap** for the water flow is used. If this parameter is set to an invalid value, 0 vp is used.|
181| rowsGap | [Dimension](ts-types.md#dimension10) | No| Gap between rows. If this parameter is not set, the value of **rowsGap** for the water flow is used. If this parameter is set to an invalid value, 0 vp is used.|
182| margin | [Margin](ts-types.md#margin) \| [Dimension](ts-types.md#dimension10) | No| Padding of the section. A value of the Length type specifies the margin for all the four sides.<br>Default value: **0**<br>Unit: vp<br>When **margin** is set to a percentage, the width of the **WaterFlow** component is used as the base value for the top, bottom, left, and right margins.|
183| onGetItemMainSizeByIndex | [GetItemMainSizeByIndex](#getitemmainsizebyindex12) | No| Callback used to obtain the main axis size, in vp, of the water flow item at a specified index during the layout process of the **WaterFlow** component. For a vertical **WaterFlow** component, this size refers to the height, and for a horizontal **WaterFlow** component, it refers to the width.<br>**NOTE**<br>1. When both **onGetItemMainSizeByIndex** and the width or height attribute of the water flow item are used, the main axis size is determined by the return value of **onGetItemMainSizeByIndex**, which will override the main axis length of water flow item.<br>2. Using **onGetItemMainSizeByIndex** can improve the efficiency of jumping to a specific position or index in the **WaterFlow** component. Avoid mixing the use of **onGetItemMainSizeByIndex** with sections that do not have it set, as this can cause layout exceptions.<br>3. If **onGetItemMainSizeByIndex** returns a negative number, the height of the water flow item is 0.|
184
185
186## GetItemMainSizeByIndex<sup>12+</sup>
187
188type GetItemMainSizeByIndex = (index: number) => number
189
190Obtains the main axis size of a specified water flow item based on its index.
191
192**Atomic service API**: This API can be used in atomic services since API version 12.
193
194**System capability**: SystemCapability.ArkUI.ArkUI.Full
195
196**Parameters**
197
198| Name  | Type                           | Mandatory  | Description                  |
199| ---- | ----------------------------- | ---- | -------------------- |
200| index | number | Yes   | Index of the target water flow item.|
201
202**Return value**
203
204| Type                                                        | Description                                                        |
205| ------------------------------------------------------------ | ------------------------------------------------------------ |
206| number | Main axis size, in vp, of the water flow item at the specified index, which is the height for a vertical **WaterFlow** component and the width for a horizontal **WaterFlow** component.|
207
208## WaterFlowLayoutMode<sup>12+</sup>
209
210**Atomic service API**: This API can be used in atomic services since API version 12.
211
212**System capability**: SystemCapability.ArkUI.ArkUI.Full
213
214| Name| Value| Description|
215| ------ | ------ | -------------------- |
216| ALWAYS_TOP_DOWN | 0 | Default layout mode where water flow items are arranged from top to bottom. Items in the viewport depend on the layout of all items above them. As such, in cases of redirection or switching the number of columns, the layout of all items above the viewport must be recalculated.|
217| SLIDING_WINDOW | 1 | Sliding window mode. This mode only takes into account the layout in the viewport, without depending on water flow items above the viewport. As such, in cases of redirection backward or switching the number of columns, only the water flow items within the viewport need to be laid out. This mode is recommended for applications that involves frequent switching between different numbers of columns.<br>**NOTE**<br>1. During a non-animated redirection to a distant location, water flow items are laid out forward or backward based on the target position. If the user then swipes back to the position prior to the redirection, the layout of the content may not be consistent with its previous state. This can lead to misalignment of the top nodes when the user swipes back to the top after the redirection. To counteract this issue, in this layout mode, the layout will be automatically adjusted after reaching the top of the viewport to ensure that the top is aligned. If there are multiple sections, adjustments will be made to the sections within the viewport when scrolling ends.<br> 2. The mode does not support the use of scrollbars; they will not be displayed even if set.<br> 3. This mode does not support the [scrollTo](ts-container-scroll.md#scrollto) API of [scroller](#waterflowoptions).<br> 4. The total offset returned by the [currentOffset](ts-container-scroll.md#currentoffset) API of [scroller](#waterflowoptions) is inaccurate after a redirection or data update. This offset will be recalibrated when the user swipes back to the top.<br> 5. If a jump action (for example, by calling [scrollToIndex](ts-container-scroll.md#scrolltoindex) without animation or [scrollEdge](ts-container-scroll.md#scrolledge)) and an input offset (such as from a swipe gesture or a scrolling animation) are both initiated within the same frame, both will be executed.<br> 6. If the [scrollToIndex](ts-container-scroll.md#scrolltoindex) API is called without animation to jump to a distant position (beyond the range of visible water flow items in the window), the total offset is not calculated in the sliding window mode, so the total offset remains unchanged. Consequently, the [onDidScroll](ts-container-scroll.md#ondidscroll12) event is not triggered.|
218
219
220## Attributes
221
222In addition to [universal attributes](ts-universal-attributes-size.md) and [scrollable component common attributes](ts-container-scrollable-common.md#attributes), the following attributes are also supported.
223
224### columnsTemplate
225
226columnsTemplate(value: string)
227
228Sets the number of columns in the layout. If this attribute is not set, one column is used by default.
229
230For example, **'1fr 1fr 2fr'** indicates three columns, with the first column taking up 1/4 of the parent component's full width, the second column 1/4, and the third column 2/4.
231
232You can use **columnsTemplate('repeat(auto-fill,track-size)')** to automatically calculate the number of columns based on the specified column width **track-size**. **repeat** and **auto-fill** are keywords. The units for **track-size** can be px, vp (default), %, or a valid number. For details, see Example 2.
233
234**Atomic service API**: This API can be used in atomic services since API version 11.
235
236**System capability**: SystemCapability.ArkUI.ArkUI.Full
237
238**Parameters**
239
240| Name| Type  | Mandatory| Description                                          |
241| ------ | ------ | ---- | ---------------------------------------------- |
242| value  | string | Yes  | Number of columns in the layout.<br>Default value: **'1fr'**|
243
244### rowsTemplate
245
246rowsTemplate(value: string)
247
248Sets the number of rows in the layout. If this attribute is not set, one row is used by default.
249
250For example, **'1fr 1fr 2fr'** indicates three rows, with the first row taking up 1/4 of the parent component's full height, the second row 1/4, and the third row 2/4.
251
252You can use **rowsTemplate('repeat(auto-fill,track-size)')** to automatically calculate the number of rows based on the specified row height **track-size**. **repeat** and **auto-fill** are keywords. The units for **track-size** can be px, vp (default), %, or a valid number.
253
254**Atomic service API**: This API can be used in atomic services since API version 11.
255
256**System capability**: SystemCapability.ArkUI.ArkUI.Full
257
258**Parameters**
259
260| Name| Type  | Mandatory| Description                                          |
261| ------ | ------ | ---- | ---------------------------------------------- |
262| value  | string | Yes  | Number of rows in the layout.<br>Default value: **'1fr'**|
263
264### itemConstraintSize
265
266itemConstraintSize(value: ConstraintSizeOptions)
267
268Sets the size constraints of the child components during layout.
269
270**Atomic service API**: This API can be used in atomic services since API version 11.
271
272**System capability**: SystemCapability.ArkUI.ArkUI.Full
273
274**Parameters**
275
276| Name| Type                                                      | Mandatory| Description      |
277| ------ | ---------------------------------------------------------- | ---- | ---------- |
278| value  | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | Yes  | Size constraints of the child components during layout. If the value specified is less than 0, this parameter does not take effect.<br>**NOTE**<br>1. If both **itemConstraintSize** and the [constraintSize](ts-universal-attributes-size.md#constraintsize) attribute of the **FlowItem** are set, the **minWidth** (or **minHeight**) will be the larger of the two values, and the **maxWidth** (or **maxHeight**) will be the smaller of the two values. The resulting values will then be used as the **constraintSize** for the **FlowItem**. 2. When only **itemConstraintSize** is set, it effectively applies a uniform size constraint to all child components in the **WaterFlow**. 3. The **itemConstraintSize** attribute, once converted to the **constraintSize** attribute of the **FlowItem** through the two methods mentioned above, follows the same rules for taking effect as the universal attribute [constraintSize](./ts-universal-attributes-size.md#constraintsize).|
279
280### columnsGap
281
282columnsGap(value: Length)
283
284Sets the gap between columns.
285
286**Atomic service API**: This API can be used in atomic services since API version 11.
287
288**System capability**: SystemCapability.ArkUI.ArkUI.Full
289
290**Parameters**
291
292| Name| Type                        | Mandatory| Description                         |
293| ------ | ---------------------------- | ---- | ----------------------------- |
294| value  | [Length](ts-types.md#length) | Yes  | Gap between columns.<br>Default value: **0**|
295
296### rowsGap
297
298rowsGap(value: Length)
299
300Sets the gap between rows.
301
302**Atomic service API**: This API can be used in atomic services since API version 11.
303
304**System capability**: SystemCapability.ArkUI.ArkUI.Full
305
306**Parameters**
307
308| Name| Type                        | Mandatory| Description                         |
309| ------ | ---------------------------- | ---- | ----------------------------- |
310| value  | [Length](ts-types.md#length) | Yes  | Gap between rows.<br>Default value: **0**|
311
312### layoutDirection
313
314layoutDirection(value: FlexDirection)
315
316Sets the main axis direction of the layout.
317
318**Atomic service API**: This API can be used in atomic services since API version 11.
319
320**System capability**: SystemCapability.ArkUI.ArkUI.Full
321
322**Parameters**
323
324| Name| Type                                               | Mandatory| Description                                             |
325| ------ | --------------------------------------------------- | ---- | ------------------------------------------------- |
326| value  | [FlexDirection](ts-appendix-enums.md#flexdirection) | Yes  | Main axis direction of the layout.<br>Default value: **FlexDirection.Column**|
327
328The priority of **layoutDirection** is higher than that of **rowsTemplate** and **columnsTemplate**. Depending on the **layoutDirection** settings, there are three layout modes:
329
330- **layoutDirection** is set to **FlexDirection.Column** or **FlexDirection.ColumnReverse**
331
332  In this case, **columnsTemplate** is valid. If it is not set, the default value is used. For example, if **columnsTemplate** is set to **"1fr 1fr"** and **rowsTemplate** **"1fr 1fr 1fr"**, child components are arranged in vertical layout, with the cross axis equally divided into two columns.
333
334- **layoutDirection** set to **FlexDirection.Row** or **FlexDirection.RowReverse**
335
336  In this case, **rowsTemplate** is valid. If it is not set, the default value is used. For example, if **columnsTemplate** is set to **"1fr 1fr"** and **rowsTemplate** **"1fr 1fr 1fr"**, child components are arranged in horizontal layout, with the cross axis equally divided into three columns.
337
338- **layoutDirection** is not set
339
340  In this case, the default value of **layoutDirection** is used, which is **FlexDirection.Column**, and **columnsTemplate** is valid. For example, if **columnsTemplate** is set to **"1fr 1fr"** and **rowsTemplate** **"1fr 1fr 1fr"**, child components are arranged in vertical layout, with the cross axis equally divided into two columns.
341
342### enableScrollInteraction<sup>10+</sup>
343
344enableScrollInteraction(value: boolean)
345
346Sets whether to support scroll gestures. When this attribute is set to **false**, scrolling by finger or mouse is not supported, but the scrolling controller API is not affected.
347
348**Atomic service API**: This API can be used in atomic services since API version 11.
349
350**System capability**: SystemCapability.ArkUI.ArkUI.Full
351
352**Parameters**
353
354| Name| Type   | Mandatory| Description                               |
355| ------ | ------- | ---- | ----------------------------------- |
356| value  | boolean | Yes  | Whether to support scroll gestures.<br>Default value: **true**|
357
358### nestedScroll<sup>10+</sup>
359
360nestedScroll(value: NestedScrollOptions)
361
362Sets the nested scrolling mode in the forward and backward directions to implement scrolling linkage with the parent component.
363
364**Atomic service API**: This API can be used in atomic services since API version 11.
365
366**System capability**: SystemCapability.ArkUI.ArkUI.Full
367
368**Parameters**
369
370| Name| Type                                                        | Mandatory| Description          |
371| ------ | ------------------------------------------------------------ | ---- | -------------- |
372| value  | [NestedScrollOptions](ts-container-scrollable-common.md#nestedscrolloptions10) | Yes  | Nested scrolling options.|
373
374### friction<sup>10+</sup>
375
376friction(value: number | Resource)
377
378Sets the friction coefficient. It applies only to gestures in the scrolling area, and it affects only indirectly the scroll chaining during the inertial scrolling process. If this attribute is set to a value less than or equal to 0, the default value is used.
379
380**Atomic service API**: This API can be used in atomic services since API version 11.
381
382**System capability**: SystemCapability.ArkUI.ArkUI.Full
383
384**Parameters**
385
386| Name| Type                                                | Mandatory| Description                                                     |
387| ------ | ---------------------------------------------------- | ---- | --------------------------------------------------------- |
388| value  | number \| [Resource](ts-types.md#resource) | Yes  | Friction coefficient.<br>Default value: **0.9** for wearable devices and **0.6** for non-wearable devices.<br>Since API version 11, the default value for non-wearable devices is **0.7**.<br>Since API version 12, the default value for non-wearable devices is **0.75**.|
389
390### cachedCount<sup>11+</sup>
391
392cachedCount(value: number)
393
394Sets the number of items to be cached. This attribute is effective only in [LazyForEach](../../../quick-start/arkts-rendering-control-lazyforeach.md). After this attribute is set, items that exceed the display and cache range are released. A value less than 0 evaluates to the default value.
395
396**Atomic service API**: This API can be used in atomic services since API version 12.
397
398**System capability**: SystemCapability.ArkUI.ArkUI.Full
399
400**Parameters**
401
402| Name| Type  | Mandatory| Description                                    |
403| ------ | ------ | ---- | ---------------------------------------- |
404| value  | number | Yes  | Number of water flow items to be preloaded (cached).<br> Default value: **1**|
405
406### cachedCount<sup>14+</sup>
407
408cachedCount(value: number, show: boolean)
409
410Sets the number of water flow items to be cached (preloaded) and specifies whether to display the cached nodes.
411
412When this attribute is used in conjunction with the [clip](ts-universal-attributes-sharp-clipping.md#clip12) or [content clipping](ts-container-scrollable-common.md#clipcontent14) attributes, the cached nodes can be displayed.
413
414In [LazyForEach](../../../quick-start/arkts-rendering-control-lazyforeach.md) and [Repeat](../../../quick-start/arkts-new-rendering-control-repeat.md) with the **virtualScroll** option enabled, water flow items that are outside the display and cache range will be released.
415
416**Atomic service API**: This API can be used in atomic services since API version 14.
417
418**System capability**: SystemCapability.ArkUI.ArkUI.Full
419
420**Parameters**
421
422| Name| Type  | Mandatory| Description                                    |
423| ------ | ------ | ---- | ---------------------------------------- |
424| value  | number | Yes  | Number of water flow items to be preloaded (cached).<br> Default value: **1**|
425| show  | boolean | Yes  | Whether to display the cached water flow items.<br> Default value: **false**|
426
427## Events
428
429In addition to [universal events](ts-universal-events-click.md) and [scrollable component common events](ts-container-scrollable-common.md#events), the following events are also supported.
430
431### onReachStart
432
433onReachStart(event: () => void)
434
435Triggered when the component reaches the start.
436
437**Atomic service API**: This API can be used in atomic services since API version 11.
438
439**System capability**: SystemCapability.ArkUI.ArkUI.Full
440
441### onReachEnd
442
443onReachEnd(event: () => void)
444
445Triggered when the component reaches the end position.
446
447**Atomic service API**: This API can be used in atomic services since API version 11.
448
449**System capability**: SystemCapability.ArkUI.ArkUI.Full
450
451### onScrollFrameBegin<sup>10+</sup>
452
453onScrollFrameBegin(event: (offset: number, state: ScrollState) => { offsetRemain: number; })
454
455Triggered when the component starts to scroll. The input parameters indicate the amount by which the component will scroll. The event handler then works out the amount by which the component needs to scroll based on the real-world situation and returns the result.
456
457This event is triggered when the user starts dragging the component or the component starts inertial scrolling. It is not triggered when the component rebounds, the scrolling controller is used, or the scrollbar is dragged.
458
459**Atomic service API**: This API can be used in atomic services since API version 11.
460
461**System capability**: SystemCapability.ArkUI.ArkUI.Full
462
463**Parameters**
464
465| Name| Type                                                   | Mandatory| Description                      |
466| ------ | ------------------------------------------------------- | ---- | -------------------------- |
467| offset | number                                                  | Yes  | Amount to scroll by, in vp.|
468| state  | [ScrollState](ts-container-list.md#scrollstate) | Yes  | Current scroll state.            |
469
470**Return value**
471
472| Type                    | Description                |
473| ------------------------ | -------------------- |
474| { offsetRemain: number } | Actual amount by which the component scrolls, in vp.|
475
476### onScrollIndex<sup>11+</sup>
477
478onScrollIndex(event: (first: number, last: number) => void)
479
480Triggered when the first or last item displayed in the component changes. It is triggered once when the component is initialized.
481
482This event is triggered when either of the preceding indexes changes.
483
484**Atomic service API**: This API can be used in atomic services since API version 11.
485
486**System capability**: SystemCapability.ArkUI.ArkUI.Full
487
488**Parameters**
489
490| Name| Type  | Mandatory| Description                                 |
491| ------ | ------ | ---- | ------------------------------------- |
492| first  | number | Yes  | Index of the first item of the component.|
493| last   | number | Yes  | Index of the last item of the component.   |
494
495## Example
496
497### Example 1: Using a Basic WaterFlow Component
498This example demonstrates the basic usage of the **WaterFlow** component, including data loading, attribute setting, and event callbacks.
499```ts
500// WaterFlowDataSource.ets
501
502// Object that implements the IDataSource API, which is used by the WaterFlow component to load data.
503export class WaterFlowDataSource implements IDataSource {
504  private dataArray: number[] = []
505  private listeners: DataChangeListener[] = []
506
507  constructor() {
508    for (let i = 0; i < 100; i++) {
509      this.dataArray.push(i)
510    }
511  }
512
513  // Obtain the data corresponding to the specified index.
514  public getData(index: number): number {
515    return this.dataArray[index]
516  }
517
518  // Notify the controller of data reloading.
519  notifyDataReload(): void {
520    this.listeners.forEach(listener => {
521      listener.onDataReloaded()
522    })
523  }
524
525  // Notify the controller of data addition.
526  notifyDataAdd(index: number): void {
527    this.listeners.forEach(listener => {
528      listener.onDataAdd(index)
529    })
530  }
531
532  // Notify the controller of data changes.
533  notifyDataChange(index: number): void {
534    this.listeners.forEach(listener => {
535      listener.onDataChange(index)
536    })
537  }
538
539  // Notify the controller of data deletion.
540  notifyDataDelete(index: number): void {
541    this.listeners.forEach(listener => {
542      listener.onDataDelete(index)
543    })
544  }
545
546  // Notify the controller of the data location change.
547  notifyDataMove(from: number, to: number): void {
548    this.listeners.forEach(listener => {
549      listener.onDataMove(from, to)
550    })
551  }
552
553  // Notify the controller of batch data modification.
554  notifyDatasetChange(operations: DataOperation[]): void {
555    this.listeners.forEach(listener => {
556      listener.onDatasetChange(operations);
557    })
558  }
559
560  // Obtain the total number of data records.
561  public totalCount(): number {
562    return this.dataArray.length
563  }
564
565  // Register the data change listener.
566  registerDataChangeListener(listener: DataChangeListener): void {
567    if (this.listeners.indexOf(listener) < 0) {
568      this.listeners.push(listener)
569    }
570  }
571
572  // Unregister the data change listener.
573  unregisterDataChangeListener(listener: DataChangeListener): void {
574    const pos = this.listeners.indexOf(listener)
575    if (pos >= 0) {
576      this.listeners.splice(pos, 1)
577    }
578  }
579
580  // Add data.
581  public add1stItem(): void {
582    this.dataArray.splice(0, 0, this.dataArray.length)
583    this.notifyDataAdd(0)
584  }
585
586  // Add an item to the end of the data.
587  public addLastItem(): void {
588    this.dataArray.splice(this.dataArray.length, 0, this.dataArray.length)
589    this.notifyDataAdd(this.dataArray.length - 1)
590  }
591
592  // Add an item to the position corresponding to the specified index.
593  public addItem(index: number): void {
594    this.dataArray.splice(index, 0, this.dataArray.length)
595    this.notifyDataAdd(index)
596  }
597
598  // Delete the first item.
599  public delete1stItem(): void {
600    this.dataArray.splice(0, 1)
601    this.notifyDataDelete(0)
602  }
603
604  // Delete the second item.
605  public delete2ndItem(): void {
606    this.dataArray.splice(1, 1)
607    this.notifyDataDelete(1)
608  }
609
610  // Delete the last item.
611  public deleteLastItem(): void {
612    this.dataArray.splice(-1, 1)
613    this.notifyDataDelete(this.dataArray.length)
614  }
615
616  // Delete an item at the specified index position.
617  public deleteItem(index: number): void {
618    this.dataArray.splice(index, 1)
619    this.notifyDataDelete(index)
620  }
621
622  // Reload data.
623  public reload(): void {
624    this.dataArray.splice(1, 1)
625    this.dataArray.splice(3, 2)
626    this.notifyDataReload()
627  }
628}
629```
630
631```ts
632// Index.ets
633import { WaterFlowDataSource } from './WaterFlowDataSource'
634
635@Entry
636@Component
637struct WaterFlowDemo {
638  @State minSize: number = 80
639  @State maxSize: number = 180
640  @State fontSize: number = 24
641  @State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]
642  scroller: Scroller = new Scroller()
643  dataSource: WaterFlowDataSource = new WaterFlowDataSource()
644  private itemWidthArray: number[] = []
645  private itemHeightArray: number[] = []
646
647  // Calculate the width and height of a water flow item.
648  getSize() {
649    let ret = Math.floor(Math.random() * this.maxSize)
650    return (ret > this.minSize ? ret : this.minSize)
651  }
652
653  // Set the width and height array of the water flow item.
654  setItemSizeArray() {
655    for (let i = 0; i < 100; i++) {
656      this.itemWidthArray.push(this.getSize())
657      this.itemHeightArray.push(this.getSize())
658    }
659  }
660
661  aboutToAppear() {
662    this.setItemSizeArray()
663  }
664
665  @Builder
666  itemFoot() {
667    Column() {
668      Text(`Footer`)
669        .fontSize(10)
670        .backgroundColor(Color.Red)
671        .width(50)
672        .height(50)
673        .align(Alignment.Center)
674        .margin({ top: 2 })
675    }
676  }
677
678  build() {
679    Column({ space: 2 }) {
680      WaterFlow() {
681        LazyForEach(this.dataSource, (item: number) => {
682          FlowItem() {
683            Column() {
684              Text("N" + item).fontSize(12).height('16')
685              // The image is displayed only when there is a corresponding JPG file.
686              Image('res/waterFlowTest(' + item % 5 + ').jpg')
687                .objectFit(ImageFit.Fill)
688                .width('100%')
689                .layoutWeight(1)
690            }
691          }
692          .onAppear(() => {
693            // Add data in advance when scrolling is about to end.
694            if (item + 20 == this.dataSource.totalCount()) {
695              for (let i = 0; i < 100; i++) {
696                this.dataSource.addLastItem()
697              }
698            }
699          })
700          .width('100%')
701          .height(this.itemHeightArray[item % 100])
702          .backgroundColor(this.colors[item % 5])
703        }, (item: string) => item)
704      }
705      .columnsTemplate("1fr 1fr")
706      .columnsGap(10)
707      .rowsGap(5)
708      .backgroundColor(0xFAEEE0)
709      .width('100%')
710      .height('100%')
711      .onReachStart(() => {
712        console.info('waterFlow reach start')
713      })
714      .onScrollStart(() => {
715        console.info('waterFlow scroll start')
716      })
717      .onScrollStop(() => {
718        console.info('waterFlow scroll stop')
719      })
720      .onScrollFrameBegin((offset: number, state: ScrollState) => {
721        console.info('waterFlow scrollFrameBegin offset: ' + offset + ' state: ' + state.toString())
722        return { offsetRemain: offset }
723      })
724    }
725  }
726}
727```
728
729![zh-cn_image_WaterFlow.gif](figures/waterflow-perf-demo.gif)
730
731### Example 2: Implementing Automatic Column Count Calculation
732This example showcases how to implement automatic column count calculation using the **auto-fill** feature.
733```ts
734// Index.ets
735import { WaterFlowDataSource } from './WaterFlowDataSource'
736
737@Entry
738@Component
739struct WaterFlowDemo {
740  @State minSize: number = 80
741  @State maxSize: number = 180
742  @State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]
743  dataSource: WaterFlowDataSource = new WaterFlowDataSource()
744  private itemWidthArray: number[] = []
745  private itemHeightArray: number[] = []
746
747  // Calculate the width and height of a water flow item.
748  getSize() {
749    let ret = Math.floor(Math.random() * this.maxSize)
750    return (ret > this.minSize ? ret : this.minSize)
751  }
752
753  // Set the width and height array of the water flow item.
754  setItemSizeArray() {
755    for (let i = 0; i < 100; i++) {
756      this.itemWidthArray.push(this.getSize())
757      this.itemHeightArray.push(this.getSize())
758    }
759  }
760
761  aboutToAppear() {
762    this.setItemSizeArray()
763  }
764
765  build() {
766    Column({ space: 2 }) {
767      WaterFlow() {
768        LazyForEach(this.dataSource, (item: number) => {
769          FlowItem() {
770            Column() {
771              Text("N" + item).fontSize(12).height('16')
772              Image('res/waterFlowTest(' + item % 5 + ').jpg')
773            }
774          }
775          .width('100%')
776          .height(this.itemHeightArray[item % 100])
777          .backgroundColor(this.colors[item % 5])
778        }, (item: string) => item)
779      }
780      .columnsTemplate('repeat(auto-fill,80)')
781      .columnsGap(10)
782      .rowsGap(5)
783      .padding({left:5})
784      .backgroundColor(0xFAEEE0)
785      .width('100%')
786      .height('100%')
787    }
788  }
789}
790```
791
792![waterflow_auto-fill.png](figures/waterflow_auto-fill.png)
793
794
795### Example 3: Using WaterFlowSections
796This example illustrates the initialization of **WaterFlowSections** and the different effects of various APIs such as **splice**, **push**, **update**, **values**, and **length**.
797For details about how to use these features in conjunction with state management V2, see [WaterFlow](../../../quick-start/arkts-v1-v2-migration.md#waterflow).
798```ts
799// Index.ets
800import { WaterFlowDataSource } from './WaterFlowDataSource'
801
802@Reusable
803@Component
804struct ReusableFlowItem {
805  @State item: number = 0
806
807  // Invoked when a reusable custom component is re-added to the component tree from the reuse cache. The component state variable can be updated here to display the correct content.
808  aboutToReuse(params: Record<string, number>) {
809    this.item = params.item;
810    console.info('Reuse item:' + this.item)
811  }
812
813  aboutToAppear() {
814    console.info('new item:' + this.item)
815  }
816
817  build() {
818    Image('res/waterFlowTest(' + this.item % 5 + ').jpg')
819        .overlay('N' + this.item, { align: Alignment.Top })
820        .objectFit(ImageFit.Fill)
821        .width('100%')
822        .layoutWeight(1)
823  }
824}
825
826@Entry
827@Component
828struct WaterFlowDemo {
829  minSize: number = 80
830  maxSize: number = 180
831  fontSize: number = 24
832  colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]
833  scroller: Scroller = new Scroller()
834  dataSource: WaterFlowDataSource = new WaterFlowDataSource()
835  dataCount: number = this.dataSource.totalCount()
836  private itemHeightArray: number[] = []
837  @State sections: WaterFlowSections = new WaterFlowSections()
838  sectionMargin: Margin = { top: 10, left: 5, bottom: 10, right: 5 }
839  oneColumnSection: SectionOptions = {
840    itemsCount: 4,
841    crossCount: 1,
842    columnsGap: '5vp',
843    rowsGap: 10,
844    margin: this.sectionMargin,
845    onGetItemMainSizeByIndex: (index: number) => {
846      return this.itemHeightArray[index % 100]
847    }
848  }
849  twoColumnSection: SectionOptions = {
850    itemsCount: 2,
851    crossCount: 2,
852    onGetItemMainSizeByIndex: (index: number) => {
853      return 100
854    }
855  }
856  lastSection: SectionOptions = {
857    itemsCount: 20,
858    crossCount: 2,
859    onGetItemMainSizeByIndex: (index: number) => {
860      return this.itemHeightArray[index % 100]
861    }
862  }
863
864  // Calculate the FlowItem height.
865  getSize() {
866    let ret = Math.floor(Math.random() * this.maxSize)
867    return (ret > this.minSize ? ret : this.minSize)
868  }
869
870  // Set the height array for FlowItems.
871  setItemSizeArray() {
872    for (let i = 0; i < 100; i++) {
873      this.itemHeightArray.push(this.getSize())
874    }
875  }
876
877  aboutToAppear() {
878    this.setItemSizeArray()
879    // Initialize the water flow section information.
880    let sectionOptions: SectionOptions[] = []
881    let count = 0
882    let oneOrTwo = 0
883    while (count < this.dataCount) {
884      if (this.dataCount - count < 20) {
885        this.lastSection.itemsCount = this.dataCount - count
886        sectionOptions.push(this.lastSection)
887        break;
888      }
889      if (oneOrTwo++ % 2 == 0) {
890        sectionOptions.push(this.oneColumnSection)
891        count += this.oneColumnSection.itemsCount
892      } else {
893        sectionOptions.push(this.twoColumnSection)
894        count += this.twoColumnSection.itemsCount
895      }
896    }
897    this.sections.splice(0, 0, sectionOptions)
898  }
899
900  build() {
901    Column({ space: 2 }) {
902      Row() {
903        Button('splice')
904          .height('5%')
905          .onClick(() => {
906            // Replace all sections with a new section. Ensure that the number of data array items in LazyForEach is the same as the value of itemsCount of the new section.
907            let totalCount: number = this.dataSource.totalCount()
908            let newSection: SectionOptions = {
909              itemsCount: totalCount,
910              crossCount: 2,
911              onGetItemMainSizeByIndex: (index: number) => {
912                return this.itemHeightArray[index % 100]
913              }
914            }
915            let oldLength: number = this.sections.length()
916            this.sections.splice(0, oldLength, [newSection])
917          })
918          .margin({ top: 10, left: 20 })
919        Button('update')
920          .height('5%')
921          .onClick(() => {
922            // Add four FlowItems to the second section. Ensure that the number of data array items in LazyForEach is the same as the sum of itemsCount values of all sections.
923            let newSection: SectionOptions = {
924              itemsCount: 6,
925              crossCount: 3,
926              columnsGap: 5,
927              rowsGap: 10,
928              margin: this.sectionMargin,
929              onGetItemMainSizeByIndex: (index: number) => {
930                return this.itemHeightArray[index % 100]
931              }
932            }
933            this.dataSource.addItem(this.oneColumnSection.itemsCount)
934            this.dataSource.addItem(this.oneColumnSection.itemsCount + 1)
935            this.dataSource.addItem(this.oneColumnSection.itemsCount + 2)
936            this.dataSource.addItem(this.oneColumnSection.itemsCount + 3)
937            const result: boolean = this.sections.update(1, newSection)
938            console.info('update:' + result)
939          })
940          .margin({ top: 10, left: 20 })
941        Button('delete')
942          .height('5%')
943          .onClick(() => {
944            // Click Update and then Delete.
945            let newSection: SectionOptions = {
946              itemsCount: 2,
947              crossCount: 2,
948              columnsGap: 5,
949              rowsGap: 10,
950              margin: this.sectionMargin,
951              onGetItemMainSizeByIndex: (index: number) => {
952                return this.itemHeightArray[index % 100]
953              }
954            }
955            this.dataSource.deleteItem(this.oneColumnSection.itemsCount)
956            this.dataSource.deleteItem(this.oneColumnSection.itemsCount)
957            this.dataSource.deleteItem(this.oneColumnSection.itemsCount)
958            this.dataSource.deleteItem(this.oneColumnSection.itemsCount)
959            this.sections.update(1, newSection)
960          })
961          .margin({ top: 10, left: 20 })
962        Button('values')
963          .height('5%')
964          .onClick(() => {
965            const sections: Array<SectionOptions> = this.sections.values();
966            for (const value of sections) {
967              console.log(JSON.stringify(value));
968            }
969            console.info('count:' + this.sections.length())
970          })
971          .margin({ top: 10, left: 20 })
972      }.margin({ bottom: 20 })
973
974      WaterFlow({ scroller: this.scroller, sections: this.sections }) {
975        LazyForEach(this.dataSource, (item: number) => {
976          FlowItem() {
977            ReusableFlowItem({ item: item })
978          }
979          .width('100%')
980          // The value of onGetItemMainSizeByIndex is used.
981          // .height(this.itemHeightArray[item % 100])
982          .backgroundColor(this.colors[item % 5])
983        }, (item: string) => item)
984      }
985      .columnsTemplate('1fr 1fr') // This attribute is ineffective when the sections parameter is used.
986      .columnsGap(10)
987      .rowsGap(5)
988      .backgroundColor(0xFAEEE0)
989      .width('100%')
990      .height('100%')
991      .layoutWeight(1)
992      .onScrollIndex((first: number, last: number) => {
993        // Add data in advance when scrolling is about to end.
994        if (last + 20 >= this.dataSource.totalCount()) {
995          for (let i = 0; i < 100; i++) {
996            this.dataSource.addLastItem()
997          }
998          // After the data source is updated, update sections synchronously and change the number of FlowItems in the last section.
999          const sections: Array<SectionOptions> = this.sections.values();
1000          let newSection: SectionOptions = sections[this.sections.length() - 1];
1001          newSection.itemsCount += 100;
1002          this.sections.update(-1, newSection);
1003        }
1004      })
1005    }
1006  }
1007}
1008```
1009
1010![waterflowSections.png](figures/waterflowSections.png)
1011
1012### Example 4: Using the Pinch Gesture to Change the Column Count
1013This example demonstrates how to use [priorityGesture](ts-gesture-settings.md) and [PinchGesture](ts-basic-gestures-pinchgesture.md) to implement the feature of using a pinch gesture to change the number of columns in a layout.
1014```ts
1015// Index.ets
1016import { WaterFlowDataSource } from './WaterFlowDataSource'
1017
1018@Reusable
1019@Component
1020struct ReusableFlowItem {
1021  @State item: number = 0
1022
1023  // Invoked when a reusable custom component is re-added to the component tree from the reuse cache. The component state variable can be updated here to display the correct content.
1024  aboutToReuse(params: Record<string, number>) {
1025    this.item = params.item;
1026    console.info('Reuse item:' + this.item)
1027  }
1028
1029  aboutToAppear() {
1030    console.info('item:' + this.item)
1031  }
1032
1033  build() {
1034    Column() {
1035      Text("N" + this.item).fontSize(12).height('16')
1036      Image('res/waterFlow (' + this.item % 5 + ').JPG')
1037        .objectFit(ImageFit.Fill)
1038        .width('100%')
1039        .layoutWeight(1)
1040    }
1041  }
1042}
1043
1044@Entry
1045@Component
1046struct WaterFlowDemo {
1047  minSize: number = 80
1048  maxSize: number = 180
1049  colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]
1050  @State columns: number = 2
1051  dataSource: WaterFlowDataSource = new WaterFlowDataSource()
1052  private itemWidthArray: number[] = []
1053  private itemHeightArray: number[] = []
1054
1055  // Calculate the width and height of a water flow item.
1056  getSize() {
1057    let ret = Math.floor(Math.random() * this.maxSize)
1058    return (ret > this.minSize ? ret : this.minSize)
1059  }
1060
1061  // Set the width and height array of the water flow item.
1062  setItemSizeArray() {
1063    for (let i = 0; i < 100; i++) {
1064      this.itemWidthArray.push(this.getSize())
1065      this.itemHeightArray.push(this.getSize())
1066    }
1067  }
1068
1069  aboutToAppear() {
1070    let lastCount = AppStorage.get<number>('columnsCount')
1071    if (typeof lastCount != 'undefined') {
1072      this.columns = lastCount
1073    }
1074    this.setItemSizeArray()
1075  }
1076
1077  build() {
1078    Column({ space: 2 }) {
1079      Row() {
1080        Text('Pinch to change the number of columns')
1081          .height('5%')
1082          .margin({ top: 10, left: 20 })
1083      }
1084
1085      WaterFlow() {
1086        LazyForEach(this.dataSource, (item: number) => {
1087          FlowItem() {
1088            ReusableFlowItem({ item: item })
1089          }
1090          .width('100%')
1091          .height(this.itemHeightArray[item % 100])
1092          .backgroundColor(this.colors[item % 5])
1093        }, (item: string) => item)
1094      }
1095      .columnsTemplate('1fr '.repeat(this.columns))
1096      .columnsGap(10)
1097      .rowsGap(5)
1098      .backgroundColor(0xFAEEE0)
1099      .width('100%')
1100      .height('100%')
1101      .layoutWeight(1)
1102      // Switching the number of columns triggers a reordering animation for the item positions.
1103      .animation({
1104        duration: 300,
1105        curve: Curve.Smooth
1106      })
1107      .priorityGesture(
1108        PinchGesture()
1109          .onActionEnd((event: GestureEvent) => {
1110            console.info('end scale:' + event.scale)
1111            // When a user performs a pinch-to-zoom gesture by moving their fingers apart, and the number of columns decreases to a certain threshold (in this case, 2), it will cause the items to enlarge.
1112            if (event.scale > 2) {
1113              this.columns--
1114            } else if (event.scale < 0.6) {
1115              this.columns++
1116            }
1117            // You can set the maximum and minimum number of columns based on the device screen width. Here, the minimum number of columns is 1, and the maximum number of columns is 4.
1118            this.columns = Math.min(4, Math.max(1, this.columns));
1119            AppStorage.setOrCreate<number>('columnsCount', this.columns)
1120          })
1121      )
1122    }
1123  }
1124}
1125```
1126
1127![pinch](figures/waterflow-pinch.gif)
1128
1129### Example 5: Setting the Edge Fading Effect
1130This example demonstrates how to enable the edge fading effect for the **WaterFlow** component using the [fadingEdge](ts-container-scrollable-common.md#fadingedge14) API and set the length of the fading edge using the **fadingEdgeLength** parameter.
1131```ts
1132// Index.ets
1133import { LengthMetrics } from '@kit.ArkUI'
1134import { WaterFlowDataSource } from './WaterFlowDataSource'
1135@Entry
1136@Component
1137struct WaterFlowDemo {
1138  @State minSize: number = 80
1139  @State maxSize: number = 180
1140  @State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]
1141  dataSource: WaterFlowDataSource = new WaterFlowDataSource()
1142  scroller: Scroller = new Scroller()
1143  private itemWidthArray: number[] = []
1144  private itemHeightArray: number[] = []
1145
1146  // Calculate the width and height of a water flow item.
1147  getSize() {
1148    let ret = Math.floor(Math.random() * this.maxSize)
1149    return (ret > this.minSize ? ret : this.minSize)
1150  }
1151
1152  // Set the width and height array of the water flow item.
1153  setItemSizeArray() {
1154    for (let i = 0; i < 100; i++) {
1155      this.itemWidthArray.push(this.getSize())
1156      this.itemHeightArray.push(this.getSize())
1157    }
1158  }
1159
1160  aboutToAppear() {
1161    this.setItemSizeArray()
1162  }
1163
1164  build() {
1165    Column({ space: 2 }) {
1166
1167      WaterFlow({ scroller:this.scroller }) {
1168        LazyForEach(this.dataSource, (item: number) => {
1169          FlowItem() {
1170            Column() {
1171              Text("N" + item).fontSize(12).height('16')
1172            }
1173          }
1174          .width('100%')
1175          .height(this.itemHeightArray[item % 100])
1176          .backgroundColor(this.colors[item % 5])
1177        }, (item: string) => item)
1178      }
1179      .columnsTemplate('repeat(auto-fill,80)')
1180      .columnsGap(10)
1181      .rowsGap(5)
1182      .height('90%')
1183      .fadingEdge(true,{fadingEdgeLength:LengthMetrics.vp(80)})
1184
1185    }
1186  }
1187}
1188```
1189
1190![fadingEdge_waterFlow](figures/fadingEdge_waterFlow.gif)
1191