• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# WaterFlow
2
3
4瀑布流容器,由“行”和“列”分割的单元格所组成,通过容器自身的排列规则,将不同大小的“项目”自上而下,如瀑布般紧密布局。
5
6
7> **说明:**
8>
9> 该组件从API version 9 开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
10
11
12## 子组件
13
14
15仅支持[FlowItem](ts-container-flowitem.md)子组件,支持渲染控制类型([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)和[Repeat](../../../quick-start/arkts-new-rendering-control-repeat.md))。
16
17>  **说明:**
18>
19>  WaterFlow子组件的visibility属性设置为None时不显示,但该子组件周围的columnsGap、rowsGap、margin仍会生效。
20
21## 接口
22
23
24WaterFlow(options?:  WaterFlowOptions)
25
26创建瀑布流容器。
27
28**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
29
30**系统能力:** SystemCapability.ArkUI.ArkUI.Full
31
32**参数:**
33
34| 参数名 | 类型 | 必填 | 说明 |
35| -------- | -------- | -------- | -------- |
36| options |  [WaterFlowOptions](#waterflowoptions对象说明)| 否 | 瀑布流组件参数。 |
37
38
39## WaterFlowOptions对象说明
40
41瀑布流组件参数对象。
42
43**系统能力:** SystemCapability.ArkUI.ArkUI.Full
44
45| 名称     | 类型                                        | 必填 | 说明                                     |
46| ---------- | ----------------------------------------------- | ------ | -------------------------------------------- |
47| footer |  [CustomBuilder](ts-types.md#custombuilder8) | 否   | 设置WaterFlow尾部组件。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
48| scroller | [Scroller](ts-container-scroll.md#scroller) | 否   | 可滚动组件的控制器,与可滚动组件绑定。<br/>**说明:** <br/>不允许和其他滚动类组件,如:[List](ts-container-list.md)、[Grid](ts-container-grid.md)、[Scroll](ts-container-scroll.md)等绑定同一个滚动控制对象。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 |
49| sections<sup>12+</sup> |  [WaterFlowSections](#waterflowsections12) | 否   | 设置FlowItem分组,实现同一个瀑布流组件内部各分组使用不同列数混合布局。<br/>**说明:** <br/>1. 使用分组混合布局时会忽略columnsTemplate和rowsTemplate属性。<br/>2. 使用分组混合布局时不支持单独设置footer,可以使用最后一个分组作为尾部组件。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。  |
50| layoutMode<sup>12+</sup> |[WaterFlowLayoutMode](#waterflowlayoutmode12枚举说明) | 否 | 设置WaterFlow的布局模式,根据使用场景选择更切合的模式。<br/>**说明:** <br/>默认值:[ALWAYS_TOP_DOWN](#waterflowlayoutmode12枚举说明)。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
51
52
53## WaterFlowSections<sup>12+</sup>
54
55瀑布流分组信息。
56
57> **说明:**
58>
59> 使用splice、push、update修改分组信息后需要保证所有分组子节点总数与瀑布流实际子节点总数一致,否则会出现瀑布流因为不能正常布局而无法滑动的问题。
60
61### constructor
62
63constructor()
64
65创建一个瀑布流分组。
66
67**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
68
69**系统能力:** SystemCapability.ArkUI.ArkUI.Full
70
71### splice<sup>12+</sup>
72
73splice(start: number, deleteCount?: number, sections?: Array\<SectionOptions\>): boolean
74
75移除或者替换已存在的分组和/或添加新分组。
76
77**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
78
79**系统能力:** SystemCapability.ArkUI.ArkUI.Full
80
81**参数:**
82
83| 参数名   | 类型                            | 必填   | 说明                   |
84| ---- | ----------------------------- | ---- | -------------------- |
85| start | number | 是    | 从0开始计算的索引,会转换为整数,表示要开始改变分组的位置。<br/>**说明:** <br/>1. 如果索引是负数,则从末尾开始计算,使用`start + WaterFlowSections.length()`。<br/>2. 如果 `start < -WaterFlowSections.length()`,则使用0。<br/>3. 如果 `start >= WaterFlowSections.length()`,则在最后添加新分组。 |
86| deleteCount | number | 否    | 表示要从start开始删除的分组数量。<br/>**说明:** <br/>1. 如果省略了deleteCount,或者其值大于或等于由start指定的位置到WaterFlowSections末尾的分组数量,那么从start到WaterFlowSections末尾的所有分组将被删除。<br/>2. 如果deleteCount是0或者负数,则不会删除任何分组。 |
87| sections | Array<[SectionOptions](#sectionoptions12对象说明)> | 否    | 表示要从start开始加入的分组。如果不指定,`splice()`将只从瀑布流中删除分组。 |
88
89**返回值:**
90
91| 类型                                                         | 说明                                                         |
92| ------------------------------------------------------------ | ------------------------------------------------------------ |
93| boolean | 分组是否修改成功,要加入的分组中有任意分组的itemsCount不是正整数时返回false。 |
94
95
96### push<sup>12+</sup>
97
98push(section: SectionOptions): boolean
99
100将指定分组添加到瀑布流末尾。
101
102**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
103
104**系统能力:** SystemCapability.ArkUI.ArkUI.Full
105
106**参数:**
107
108| 参数名   | 类型                            | 必填   | 说明                   |
109| ---- | ----------------------------- | ---- | -------------------- |
110| section | [SectionOptions](#sectionoptions12对象说明) | 是    | 添加到瀑布流末尾的分组。 |
111
112**返回值:**
113
114| 类型                                                         | 说明                                                         |
115| ------------------------------------------------------------ | ------------------------------------------------------------ |
116| boolean | 分组是否添加成功,新分组的itemsCount不是正整数时返回false。 |
117
118### update<sup>12+</sup>
119
120update(sectionIndex: number, section: SectionOptions): boolean
121
122修改指定索引分组的配置信息。
123
124**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
125
126**系统能力:** SystemCapability.ArkUI.ArkUI.Full
127
128**参数:**
129
130| 参数名   | 类型                            | 必填   | 说明                   |
131| ---- | ----------------------------- | ---- | -------------------- |
132| sectionIndex | number | 是    | 从0开始计算的索引,会转换为整数,表示要修改的分组的位置。<br/>**说明:** <br/>1. 如果索引是负数,则从末尾开始计算,使用`sectionIndex + WaterFlowSections.length()`。<br/>2. 如果`sectionIndex < -WaterFlowSections.length()`,则使用0。<br/>3. 如果`sectionIndex >= WaterFlowSections.length()`,则在最后添加新分组。 |
133| section | [SectionOptions](#sectionoptions12对象说明) | 是    | 新的分组信息。 |
134
135**返回值:**
136
137| 类型                                                         | 说明                                                         |
138| ------------------------------------------------------------ | ------------------------------------------------------------ |
139| boolean | 分组是否更新成功,新分组的itemsCount不是正整数时返回false。 |
140
141### values<sup>12+</sup>
142
143values(): Array\<SectionOptions\>
144
145获取瀑布流中所有分组配置信息。
146
147**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
148
149**系统能力:** SystemCapability.ArkUI.ArkUI.Full
150
151**返回值:**
152
153| 类型                                                         | 说明                                                         |
154| ------------------------------------------------------------ | ------------------------------------------------------------ |
155| Array<[SectionOptions](#sectionoptions12对象说明)> | 瀑布流中所有分组配置信息。 |
156
157### length<sup>12+</sup>
158
159length(): number
160
161获取瀑布流中分组数量。
162
163**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
164
165**系统能力:** SystemCapability.ArkUI.ArkUI.Full
166
167**返回值:**
168
169| 类型                                                         | 说明                                                         |
170| ------------------------------------------------------------ | ------------------------------------------------------------ |
171| number | 瀑布流中分组数量。 |
172
173## SectionOptions<sup>12+</sup>对象说明
174
175FlowItem分组配置信息。
176
177**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
178
179**系统能力:** SystemCapability.ArkUI.ArkUI.Full
180
181| 名称 | 类型 | 必填 | 说明 |
182|------|-----|-----|-----|
183| itemsCount | number | 是 | 分组中FlowItem数量,必须是正整数。若splice、push、update方法收到的分组中有分组的itemsCount小于0,则不会执行该方法。 |
184| crossCount | number | 否 | 纵向布局时为列数,横向布局时为行数,默认值:1。小于1的按默认值处理。 |
185| columnsGap | [Dimension](ts-types.md#dimension10) | 否 | 该分组的列间距,不设置时使用瀑布流的columnsGap,设置非法值时使用0vp。 |
186| rowsGap | [Dimension](ts-types.md#dimension10) | 否 | 该分组的行间距,不设置时使用瀑布流的rowsGap,设置非法值时使用0vp。 |
187| margin | [Margin](ts-types.md#margin) \| [Dimension](ts-types.md#dimension10) | 否 | 该分组的外边距参数为Length类型时,四个方向外边距同时生效。<br>默认值:0<br>单位:vp<br>margin设置百分比时,上下左右外边距均以瀑布流的width作为基础值。 |
188| onGetItemMainSizeByIndex | [GetItemMainSizeByIndex](#getitemmainsizebyindex12) | 否 | 瀑布流组件布局过程中获取指定index的FlowItem的主轴大小,纵向瀑布流时为高度,横向瀑布流时为宽度,单位vp。<br/>**说明:** <br/>1. 同时使用onGetItemMainSizeByIndex和FlowItem的宽高属性时,主轴大小以onGetItemMainSizeByIndex返回结果为准,onGetItemMainSizeByIndex会覆盖FlowItem的主轴长度。<br/>2. 使用onGetItemMainSizeByIndex可以提高瀑布流跳转到指定位置或index时的效率,避免混用设置onGetItemMainSizeByIndex和未设置的分组,会导致布局异常。<br/>3. onGetItemMainSizeByIndex返回负数时FlowItem高度为0。 |
189
190
191## GetItemMainSizeByIndex<sup>12+</sup>
192
193type GetItemMainSizeByIndex = (index: number) => number
194
195根据index获取指定Item的主轴大小。
196
197**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
198
199**系统能力:** SystemCapability.ArkUI.ArkUI.Full
200
201**参数:**
202
203| 参数名   | 类型                            | 必填   | 说明                   |
204| ---- | ----------------------------- | ---- | -------------------- |
205| index | number | 是    | FlowItem在WaterFlow中的索引。<br/>取值范围:[0, 子节点总数-1] |
206
207**返回值:**
208
209| 类型                                                         | 说明                                                         |
210| ------------------------------------------------------------ | ------------------------------------------------------------ |
211| number | 指定index的FlowItem的主轴大小,纵向瀑布流时为高度,横向瀑布流时为宽度,单位vp。 |
212
213## WaterFlowLayoutMode<sup>12+</sup>枚举说明
214
215瀑布流组件布局模式枚举。
216
217**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
218
219**系统能力:** SystemCapability.ArkUI.ArkUI.Full
220
221| 名称 | 值 | 说明 |
222| ------ | ------ | -------------------- |
223| ALWAYS_TOP_DOWN | 0 | 默认的从上到下的布局模式。视窗内的FlowItem依赖视窗上方所有FlowItem的布局信息。因此跳转或切换列数时,需要计算出上方所有的FlowItem的布局信息。 |
224| SLIDING_WINDOW | 1 | 移动窗口式的布局模式。只考虑视窗内的布局信息,对视窗上方的FlowItem没有依赖关系,因此向后跳转或切换列数时只需要布局视窗内的FlowItem。有频繁切换列数的场景的应用建议使用该模式。 <br/>**说明:** <br/>1. 无动画跳转到较远的位置时,会以目标位置为基准,向前或向后布局FlowItem。这之后如果滑回跳转前的位置,内容的布局效果可能和之前不一致。 这个效果会导致跳转后回滑到顶部时,顶部节点可能不对齐。所以该布局模式下会在滑动到顶部后自动调整布局,保证顶部对齐。在有多个分组的情况下,会在滑动结束时调整在视窗内的分组。<br/> 2. 该模式不支持使用滚动条,就算设置了滚动条也无法显示。 <br/> 3. 不支持[scroller](#waterflowoptions对象说明)的[scrollTo](ts-container-scroll.md#scrollto)接口。 <br/> 4. [scroller](#waterflowoptions对象说明)的[currentOffset](ts-container-scroll.md#currentoffset)接口返回的总偏移量在触发跳转或数据更新后不准确,在回滑到顶部时会重新校准。 <br/> 5. 如果在同一帧内调用跳转(如无动画的[scrollToIndex](ts-container-scroll.md#scrolltoindex)、[scrollEdge](ts-container-scroll.md#scrolledge))和输入偏移量(如滑动手势或滚动动画),两者都会生效。 <br/> 6. 调用无动画的[scrollToIndex](ts-container-scroll.md#scrolltoindex)进行跳转,如果跳转到较远位置(超过视窗内的FlowItem数量的位置)时,由于移动窗口模式对总偏移量没有估算,此时总偏移量没有变化,所以不会触发[onDidScroll](ts-container-scroll.md#ondidscroll12)事件。 |
225
226
227## 属性
228
229除支持[通用属性](ts-component-general-attributes.md)和[滚动组件通用属性](ts-container-scrollable-common.md#属性)外,还支持以下属性:
230
231### columnsTemplate
232
233columnsTemplate(value: string)
234
235设置当前瀑布流组件布局列的数量,不设置时默认1列。
236
237例如, '1fr 1fr 2fr' 是将父组件分3列,将父组件允许的宽分为4等份,第一列占1份,第二列占1份,第三列占2份。
238
239可使用columnsTemplate('repeat(auto-fill,track-size)')根据给定的列宽track-size自动计算列数,其中repeat、auto-fill为关键字,track-size为可设置的宽度,支持的单位包括px、vp、%或有效数字,默认单位为vp,使用方法参见示例2。
240
241**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
242
243**系统能力:** SystemCapability.ArkUI.ArkUI.Full
244
245**参数:**
246
247| 参数名 | 类型   | 必填 | 说明                                           |
248| ------ | ------ | ---- | ---------------------------------------------- |
249| value  | string | 是   | 当前瀑布流组件布局列的数量。<br/>默认值:'1fr' |
250
251### rowsTemplate
252
253rowsTemplate(value: string)
254
255设置当前瀑布流组件布局行的数量,不设置时默认1行。
256
257例如, '1fr 1fr 2fr'是将父组件分三行,将父组件允许的高分为4等份,第一行占1份,第二行占一份,第三行占2份。
258
259可使用rowsTemplate('repeat(auto-fill,track-size)')根据给定的行高track-size自动计算行数,其中repeat、auto-fill为关键字,track-size为可设置的高度,支持的单位包括px、vp、%或有效数字,默认单位为vp。
260
261**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
262
263**系统能力:** SystemCapability.ArkUI.ArkUI.Full
264
265**参数:**
266
267| 参数名 | 类型   | 必填 | 说明                                           |
268| ------ | ------ | ---- | ---------------------------------------------- |
269| value  | string | 是   | 当前瀑布流组件布局行的数量。<br/>默认值:'1fr' |
270
271### itemConstraintSize
272
273itemConstraintSize(value: ConstraintSizeOptions)
274
275设置约束尺寸,子组件布局时,进行尺寸范围限制。
276
277**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
278
279**系统能力:** SystemCapability.ArkUI.ArkUI.Full
280
281**参数:**
282
283| 参数名 | 类型                                                       | 必填 | 说明       |
284| ------ | ---------------------------------------------------------- | ---- | ---------- |
285| value  | [ConstraintSizeOptions](ts-types.md#constraintsizeoptions) | 是   | 约束尺寸。设置小于0的值,参数不生效。 <br/>**说明:**<br/>1.同时设置itemConstraintSize和FlowItem的[constraintSize](ts-universal-attributes-size.md#constraintsize)属性时,minWidth/minHeight会取其中的最大值,maxWidth/maxHeight会取其中的最小值,调整后的值作为FlowItem的constraintSize处理。2.只设置itemConstraintSize时,相当于对WaterFlow所有子组件设置了相同的constraintSize。3.itemConstraintSize通过以上两种方式转换成FlowItem的constraintSize后的生效规则与通用属性[constraintSize](./ts-universal-attributes-size.md#constraintsize)相同。|
286
287### columnsGap
288
289columnsGap(value: Length)
290
291设置列与列的间距。
292
293**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
294
295**系统能力:** SystemCapability.ArkUI.ArkUI.Full
296
297**参数:**
298
299| 参数名 | 类型                         | 必填 | 说明                          |
300| ------ | ---------------------------- | ---- | ----------------------------- |
301| value  | [Length](ts-types.md#length) | 是   | 列与列的间距。 <br/>默认值:0<br/>取值范围:[0, +∞) |
302
303### rowsGap
304
305rowsGap(value: Length)
306
307设置行与行的间距。
308
309**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
310
311**系统能力:** SystemCapability.ArkUI.ArkUI.Full
312
313**参数:**
314
315| 参数名 | 类型                         | 必填 | 说明                          |
316| ------ | ---------------------------- | ---- | ----------------------------- |
317| value  | [Length](ts-types.md#length) | 是   | 行与行的间距。 <br/>默认值:0<br/>取值范围:[0, +∞) |
318
319### layoutDirection
320
321layoutDirection(value: FlexDirection)
322
323设置布局的主轴方向。
324
325**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
326
327**系统能力:** SystemCapability.ArkUI.ArkUI.Full
328
329**参数:**
330
331| 参数名 | 类型                                                | 必填 | 说明                                              |
332| ------ | --------------------------------------------------- | ---- | ------------------------------------------------- |
333| value  | [FlexDirection](ts-appendix-enums.md#flexdirection) | 是   | 布局的主轴方向。<br/>默认值:FlexDirection.Column |
334
335layoutDirection优先级高于rowsTemplate和columnsTemplate。根据layoutDirection设置情况,分为以下三种设置模式:
336
337- layoutDirection设置纵向布局(FlexDirection.ColumnFlexDirection.ColumnReverse338
339  此时columnsTemplate有效(如果未设置,取默认值)。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件纵向布局,辅轴均分成横向2列。
340
341- layoutDirection设置横向布局(FlexDirection.RowFlexDirection.RowReverse342
343  此时rowsTemplate有效(如果未设置,取默认值)。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件横向布局,辅轴均分成纵向3列。
344
345- layoutDirection未设置布局方向
346
347  布局方向为layoutDirection的默认值:FlexDirection.Column,此时columnsTemplate有效。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件纵向布局,辅轴均分成横向2列。
348
349### enableScrollInteraction<sup>10+</sup>
350
351enableScrollInteraction(value: boolean)
352
353设置是否支持滚动手势,当设置为false时,无法通过手指或者鼠标滚动,但不影响控制器的滚动接口。
354
355**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
356
357**系统能力:** SystemCapability.ArkUI.ArkUI.Full
358
359**参数:**
360
361| 参数名 | 类型    | 必填 | 说明                                |
362| ------ | ------- | ---- | ----------------------------------- |
363| value  | boolean | 是   | 是否支持滚动手势。<br/>默认值:true |
364
365### nestedScroll<sup>10+</sup>
366
367nestedScroll(value: NestedScrollOptions)
368
369设置向前向后两个方向上的嵌套滚动模式,实现与父组件的滚动联动。
370
371**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
372
373**系统能力:** SystemCapability.ArkUI.ArkUI.Full
374
375**参数:**
376
377| 参数名 | 类型                                                         | 必填 | 说明           |
378| ------ | ------------------------------------------------------------ | ---- | -------------- |
379| value  | [NestedScrollOptions](ts-container-scrollable-common.md#nestedscrolloptions10对象说明) | 是   | 嵌套滚动选项。 |
380
381### friction<sup>10+</sup>
382
383friction(value: number | Resource)
384
385设置摩擦系数,手动划动滚动区域时生效,只对惯性滚动过程有影响,对惯性滚动过程中的链式效果有间接影响。
386
387**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
388
389**系统能力:** SystemCapability.ArkUI.ArkUI.Full
390
391**参数:**
392
393| 参数名 | 类型                                                 | 必填 | 说明                                                      |
394| ------ | ---------------------------------------------------- | ---- | --------------------------------------------------------- |
395| value  | number&nbsp;\|&nbsp;[Resource](ts-types.md#resource) | 是   | 摩擦系数。<br/>默认值:非可穿戴设备为0.6,可穿戴设备为0.9。<br/>从API version 11开始,非可穿戴设备默认值为0.7。<br/>从API version 12开始,非可穿戴设备默认值为0.75。<br/>取值范围:(0, +∞),设置为小于等于0的值时,按默认值处理。 |
396
397### cachedCount<sup>11+</sup>
398
399cachedCount(value: number)
400
401设置预加载的FlowItem的数量,只在LazyForEach中生效。设置该属性后会缓存cachedCount个FlowItem。[LazyForEach](../../../quick-start/arkts-rendering-control-lazyforeach.md)超出显示和缓存范围的FlowItem会被释放。
402
403**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。
404
405**系统能力:** SystemCapability.ArkUI.ArkUI.Full
406
407**参数:**
408
409| 参数名 | 类型   | 必填 | 说明                                                         |
410| ------ | ------ | ---- | ------------------------------------------------------------ |
411| value  | number | 是   | 预加载的FlowItem的数量。 <br/> 默认值:根据屏幕内显示的节点个数设置,最大值为16。<br/>取值范围:[0, +∞),设置为小于0的值时,按1处理。 |
412
413### cachedCount<sup>14+</sup>
414
415cachedCount(count: number, show: boolean)
416
417设置预加载的FlowItem数量,并配置是否显示预加载节点。
418
419配合[裁剪](ts-universal-attributes-sharp-clipping.md#clip12)或[内容裁剪](ts-container-scrollable-common.md#clipcontent14)属性可以显示出预加载节点。
420
421[LazyForEach](../../../quick-start/arkts-rendering-control-lazyforeach.md)和开启了virtualScroll开关的[Repeat](../../../quick-start/arkts-new-rendering-control-repeat.md)超出显示和缓存范围的FlowItem会被释放。
422
423**原子化服务API:** 从API version 14开始,该接口支持在原子化服务中使用。
424
425**系统能力:** SystemCapability.ArkUI.ArkUI.Full
426
427**参数:**
428
429| 参数名 | 类型   | 必填 | 说明                                     |
430| ------ | ------ | ---- | ---------------------------------------- |
431| count  | number | 是   | 预加载的FlowItem的数量。 <br/> 默认值:根据屏幕内显示的节点个数设置,最大值为16。 |
432| show  | boolean | 是   | 被预加载的FlowItem是否需要显示。 <br/> 默认值:false,不显示预加载的FlowItem。 |
433
434## 事件
435
436除支持[通用事件](ts-component-general-events.md)和[滚动组件通用事件](ts-container-scrollable-common.md#事件)外,还支持以下事件:
437
438### onReachStart
439
440onReachStart(event: () => void)
441
442瀑布流组件到达起始位置时触发。
443
444**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
445
446**系统能力:** SystemCapability.ArkUI.ArkUI.Full
447
448### onReachEnd
449
450onReachEnd(event: () => void)
451
452瀑布流组件到底末尾位置时触发。
453
454**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
455
456**系统能力:** SystemCapability.ArkUI.ArkUI.Full
457
458### onScrollFrameBegin<sup>10+</sup>
459
460onScrollFrameBegin(event: (offset: number, state: ScrollState) => { offsetRemain: number; })
461
462瀑布流开始滑动时触发,事件参数传入即将发生的滑动量,事件处理函数中可根据应用场景计算实际需要的滑动量并作为事件处理函数的返回值返回,瀑布流将按照返回值的实际滑动量进行滑动。
463
464触发该事件的条件:手指拖动WaterFlow、WaterFlow惯性划动时每帧开始时触发;WaterFlow超出边缘回弹、使用滚动控制器和拖动滚动条的滚动不会触发。
465
466**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
467
468**系统能力:** SystemCapability.ArkUI.ArkUI.Full
469
470**参数:**
471
472| 参数名 | 类型                                                    | 必填 | 说明                       |
473| ------ | ------------------------------------------------------- | ---- | -------------------------- |
474| offset | number                                                  | 是   | 即将发生的滑动量,单位vp。 |
475| state  | [ScrollState](ts-container-list.md#scrollstate枚举说明) | 是   | 当前滑动状态。             |
476
477**返回值:**
478
479| 类型                     | 说明                 |
480| ------------------------ | -------------------- |
481| { offsetRemain: number } | 实际滑动量,单位vp。 |
482
483### onScrollIndex<sup>11+</sup>
484
485onScrollIndex(event: (first: number, last: number) => void)
486
487当前瀑布流显示的起始位置/终止位置的子组件发生变化时触发。瀑布流初始化时会触发一次。
488
489瀑布流显示区域上第一个子组件/最后一个组件的索引值有变化就会触发。
490
491**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。
492
493**系统能力:** SystemCapability.ArkUI.ArkUI.Full
494
495**参数:**
496
497| 参数名 | 类型   | 必填 | 说明                                  |
498| ------ | ------ | ---- | ------------------------------------- |
499| first  | number | 是   | 当前显示的瀑布流起始位置的索引值。<br/>取值范围:[0, 子节点总数-1] |
500| last   | number | 是   | 当前显示的瀑布流终止位置的索引值。<br/>取值范围:[0, 子节点总数-1] |
501
502## 示例
503
504### 示例1(使用基本瀑布流)
505该示例展示了WaterFlow组件数据加载处理、属性设置和事件回调等基本使用场景。
506
507<!--code_no_check-->
508```ts
509// WaterFlowDataSource.ets
510
511// 实现IDataSource接口的对象,用于瀑布流组件加载数据
512export class WaterFlowDataSource implements IDataSource {
513  private dataArray: number[] = [];
514  private listeners: DataChangeListener[] = [];
515
516  constructor() {
517    for (let i = 0; i < 100; i++) {
518      this.dataArray.push(i);
519    }
520  }
521
522  // 获取索引对应的数据
523  public getData(index: number): number {
524    return this.dataArray[index];
525  }
526
527  // 通知控制器数据重新加载
528  notifyDataReload(): void {
529    this.listeners.forEach(listener => {
530      listener.onDataReloaded();
531    })
532  }
533
534  // 通知控制器数据增加
535  notifyDataAdd(index: number): void {
536    this.listeners.forEach(listener => {
537      listener.onDataAdd(index);
538    })
539  }
540
541  // 通知控制器数据变化
542  notifyDataChange(index: number): void {
543    this.listeners.forEach(listener => {
544      listener.onDataChange(index);
545    })
546  }
547
548  // 通知控制器数据删除
549  notifyDataDelete(index: number): void {
550    this.listeners.forEach(listener => {
551      listener.onDataDelete(index);
552    })
553  }
554
555  // 通知控制器数据位置变化
556  notifyDataMove(from: number, to: number): void {
557    this.listeners.forEach(listener => {
558      listener.onDataMove(from, to);
559    })
560  }
561
562  //通知控制器数据批量修改
563  notifyDatasetChange(operations: DataOperation[]): void {
564    this.listeners.forEach(listener => {
565      listener.onDatasetChange(operations);
566    })
567  }
568
569  // 获取数据总数
570  public totalCount(): number {
571    return this.dataArray.length;
572  }
573
574  // 注册改变数据的控制器
575  registerDataChangeListener(listener: DataChangeListener): void {
576    if (this.listeners.indexOf(listener) < 0) {
577      this.listeners.push(listener);
578    }
579  }
580
581  // 注销改变数据的控制器
582  unregisterDataChangeListener(listener: DataChangeListener): void {
583    const pos = this.listeners.indexOf(listener);
584    if (pos >= 0) {
585      this.listeners.splice(pos, 1);
586    }
587  }
588
589  // 增加数据
590  public add1stItem(): void {
591    this.dataArray.splice(0, 0, this.dataArray.length);
592    this.notifyDataAdd(0);
593  }
594
595  // 在数据尾部增加一个元素
596  public addLastItem(): void {
597    this.dataArray.splice(this.dataArray.length, 0, this.dataArray.length);
598    this.notifyDataAdd(this.dataArray.length - 1);
599  }
600
601  // 在指定索引位置增加一个元素
602  public addItem(index: number): void {
603    this.dataArray.splice(index, 0, this.dataArray.length);
604    this.notifyDataAdd(index);
605  }
606
607  // 删除第一个元素
608  public delete1stItem(): void {
609    this.dataArray.splice(0, 1);
610    this.notifyDataDelete(0);
611  }
612
613  // 删除第二个元素
614  public delete2ndItem(): void {
615    this.dataArray.splice(1, 1);
616    this.notifyDataDelete(1);
617  }
618
619  // 删除最后一个元素
620  public deleteLastItem(): void {
621    this.dataArray.splice(-1, 1);
622    this.notifyDataDelete(this.dataArray.length);
623  }
624
625  // 在指定索引位置删除一个元素
626  public deleteItem(index: number): void {
627    this.dataArray.splice(index, 1);
628    this.notifyDataDelete(index);
629  }
630
631  // 重新加载数据
632  public reload(): void {
633    this.dataArray.splice(1, 1);
634    this.dataArray.splice(3, 2);
635    this.notifyDataReload();
636  }
637}
638```
639
640<!--code_no_check-->
641```ts
642// Index.ets
643import { WaterFlowDataSource } from './WaterFlowDataSource';
644
645@Entry
646@Component
647struct WaterFlowDemo {
648  @State minSize: number = 80;
649  @State maxSize: number = 180;
650  @State fontSize: number = 24;
651  @State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F];
652  scroller: Scroller = new Scroller();
653  dataSource: WaterFlowDataSource = new WaterFlowDataSource();
654  private itemWidthArray: number[] = [];
655  private itemHeightArray: number[] = [];
656
657  // 计算FlowItem宽/高
658  getSize() {
659    let ret = Math.floor(Math.random() * this.maxSize);
660    return (ret > this.minSize ? ret : this.minSize);
661  }
662
663  // 设置FlowItem的宽/高数组
664  setItemSizeArray() {
665    for (let i = 0; i < 100; i++) {
666      this.itemWidthArray.push(this.getSize());
667      this.itemHeightArray.push(this.getSize());
668    }
669  }
670
671  aboutToAppear() {
672    this.setItemSizeArray();
673  }
674
675  @Builder
676  itemFoot() {
677    Column() {
678      Text(`Footer`)
679        .fontSize(10)
680        .backgroundColor(Color.Red)
681        .width(50)
682        .height(50)
683        .align(Alignment.Center)
684        .margin({ top: 2 })
685    }
686  }
687
688  build() {
689    Column({ space: 2 }) {
690      WaterFlow() {
691        LazyForEach(this.dataSource, (item: number) => {
692          FlowItem() {
693            Column() {
694              Text("N" + item).fontSize(12).height('16')
695              // 存在对应的jpg文件才会显示图片
696              Image('res/waterFlowTest(' + item % 5 + ').jpg')
697                .objectFit(ImageFit.Fill)
698                .width('100%')
699                .layoutWeight(1)
700            }
701          }
702          .onAppear(() => {
703            // 即将触底时提前增加数据
704            if (item + 20 == this.dataSource.totalCount()) {
705              for (let i = 0; i < 100; i++) {
706                this.dataSource.addLastItem();
707              }
708            }
709          })
710          .width('100%')
711          .height(this.itemHeightArray[item % 100])
712          .backgroundColor(this.colors[item % 5])
713        }, (item: string) => item)
714      }
715      .columnsTemplate("1fr 1fr")
716      .columnsGap(10)
717      .rowsGap(5)
718      .backgroundColor(0xFAEEE0)
719      .width('100%')
720      .height('100%')
721      .onReachStart(() => {
722        console.info('waterFlow reach start');
723      })
724      .onScrollStart(() => {
725        console.info('waterFlow scroll start');
726      })
727      .onScrollStop(() => {
728        console.info('waterFlow scroll stop');
729      })
730      .onScrollFrameBegin((offset: number, state: ScrollState) => {
731        console.info('waterFlow scrollFrameBegin offset: ' + offset + ' state: ' + state.toString());
732        return { offsetRemain: offset };
733      })
734    }
735  }
736}
737```
738
739![zh-cn_image_WaterFlow.gif](figures/waterflow-perf-demo.gif)
740
741### 示例2(自动计算列数)
742该示例通过auto-fill实现了自动计算列数的效果。
743
744<!--code_no_check-->
745```ts
746// Index.ets
747import { WaterFlowDataSource } from './WaterFlowDataSource';
748
749@Entry
750@Component
751struct WaterFlowDemo {
752  @State minSize: number = 80;
753  @State maxSize: number = 180;
754  @State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F];
755  dataSource: WaterFlowDataSource = new WaterFlowDataSource();
756  private itemWidthArray: number[] = [];
757  private itemHeightArray: number[] = [];
758
759  // 计算FlowItem宽/高
760  getSize() {
761    let ret = Math.floor(Math.random() * this.maxSize);
762    return (ret > this.minSize ? ret : this.minSize);
763  }
764
765  // 设置FlowItem宽/高数组
766  setItemSizeArray() {
767    for (let i = 0; i < 100; i++) {
768      this.itemWidthArray.push(this.getSize());
769      this.itemHeightArray.push(this.getSize());
770    }
771  }
772
773  aboutToAppear() {
774    this.setItemSizeArray();
775  }
776
777  build() {
778    Column({ space: 2 }) {
779      WaterFlow() {
780        LazyForEach(this.dataSource, (item: number) => {
781          FlowItem() {
782            Column() {
783              Text("N" + item).fontSize(12).height('16')
784              Image('res/waterFlowTest(' + item % 5 + ').jpg')
785            }
786          }
787          .width('100%')
788          .height(this.itemHeightArray[item % 100])
789          .backgroundColor(this.colors[item % 5])
790        }, (item: string) => item)
791      }
792      .columnsTemplate('repeat(auto-fill,80)')
793      .columnsGap(10)
794      .rowsGap(5)
795      .padding({left:5})
796      .backgroundColor(0xFAEEE0)
797      .width('100%')
798      .height('100%')
799    }
800  }
801}
802```
803
804![waterflow_auto-fill.png](figures/waterflow_auto-fill.png)
805
806
807### 示例3(使用分组)
808该示例展示了分组的初始化以及splice、push、update、values、length等接口的不同效果。
809如果配合状态管理V2使用,详情见:[WaterFlow与makeObserved](../../../quick-start/arkts-v1-v2-migration.md#waterflow)。
810
811<!--code_no_check-->
812```ts
813// Index.ets
814import { WaterFlowDataSource } from './WaterFlowDataSource';
815
816@Reusable
817@Component
818struct ReusableFlowItem {
819  @State item: number = 0;
820
821  // 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容
822  aboutToReuse(params: Record<string, number>) {
823    this.item = params.item;
824    console.info('Reuse item:' + this.item);
825  }
826
827  aboutToAppear() {
828    console.info('new item:' + this.item);
829  }
830
831  build() {
832    Image('res/waterFlowTest(' + this.item % 5 + ').jpg')
833        .overlay('N' + this.item, { align: Alignment.Top })
834        .objectFit(ImageFit.Fill)
835        .width('100%')
836        .layoutWeight(1)
837  }
838}
839
840@Entry
841@Component
842struct WaterFlowDemo {
843  minSize: number = 80;
844  maxSize: number = 180;
845  fontSize: number = 24;
846  colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F];
847  scroller: Scroller = new Scroller();
848  dataSource: WaterFlowDataSource = new WaterFlowDataSource();
849  dataCount: number = this.dataSource.totalCount();
850  private itemHeightArray: number[] = [];
851  @State sections: WaterFlowSections = new WaterFlowSections();
852  sectionMargin: Margin = { top: 10, left: 5, bottom: 10, right: 5 };
853  oneColumnSection: SectionOptions = {
854    itemsCount: 4,
855    crossCount: 1,
856    columnsGap: '5vp',
857    rowsGap: 10,
858    margin: this.sectionMargin,
859    onGetItemMainSizeByIndex: (index: number) => {
860      return this.itemHeightArray[index % 100];
861    }
862  }
863  twoColumnSection: SectionOptions = {
864    itemsCount: 2,
865    crossCount: 2,
866    onGetItemMainSizeByIndex: (index: number) => {
867      return 100;
868    }
869  }
870  lastSection: SectionOptions = {
871    itemsCount: 20,
872    crossCount: 2,
873    onGetItemMainSizeByIndex: (index: number) => {
874      return this.itemHeightArray[index % 100];
875    }
876  }
877
878  // 计算FlowItem高度
879  getSize() {
880    let ret = Math.floor(Math.random() * this.maxSize);
881    return (ret > this.minSize ? ret : this.minSize);
882  }
883
884  // 设置FlowItem的高度数组
885  setItemSizeArray() {
886    for (let i = 0; i < 100; i++) {
887      this.itemHeightArray.push(this.getSize());
888    }
889  }
890
891  aboutToAppear() {
892    this.setItemSizeArray();
893    // 初始化瀑布流分组信息
894    let sectionOptions: SectionOptions[] = [];
895    let count = 0;
896    let oneOrTwo = 0;
897    while (count < this.dataCount) {
898      if (this.dataCount - count < 20) {
899        this.lastSection.itemsCount = this.dataCount - count;
900        sectionOptions.push(this.lastSection);
901        break;
902      }
903      if (oneOrTwo++ % 2 == 0) {
904        sectionOptions.push(this.oneColumnSection);
905        count += this.oneColumnSection.itemsCount;
906      } else {
907        sectionOptions.push(this.twoColumnSection);
908        count += this.twoColumnSection.itemsCount;
909      }
910    }
911    this.sections.splice(0, 0, sectionOptions);
912  }
913
914  build() {
915    Column({ space: 2 }) {
916      Row() {
917        Button('splice')
918          .height('5%')
919          .onClick(() => {
920            // 将所有分组替换成一个新分组,注意保证LazyForEach中数据数量和新分组itemsCount保持一致
921            let totalCount: number = this.dataSource.totalCount();
922            let newSection: SectionOptions = {
923              itemsCount: totalCount,
924              crossCount: 2,
925              onGetItemMainSizeByIndex: (index: number) => {
926                return this.itemHeightArray[index % 100];
927              }
928            }
929            let oldLength: number = this.sections.length();
930            this.sections.splice(0, oldLength, [newSection]);
931          })
932          .margin({ top: 10, left: 20 })
933        Button('update')
934          .height('5%')
935          .onClick(() => {
936            // 在第二个分组增加4个FlowItem,注意保证LazyForEach中数据数量和所有分组itemsCount的和保持一致
937            let newSection: SectionOptions = {
938              itemsCount: 6,
939              crossCount: 3,
940              columnsGap: 5,
941              rowsGap: 10,
942              margin: this.sectionMargin,
943              onGetItemMainSizeByIndex: (index: number) => {
944                return this.itemHeightArray[index % 100];
945              }
946            }
947            this.dataSource.addItem(this.oneColumnSection.itemsCount);
948            this.dataSource.addItem(this.oneColumnSection.itemsCount + 1);
949            this.dataSource.addItem(this.oneColumnSection.itemsCount + 2);
950            this.dataSource.addItem(this.oneColumnSection.itemsCount + 3);
951            const result: boolean = this.sections.update(1, newSection);
952            console.info('update:' + result);
953          })
954          .margin({ top: 10, left: 20 })
955        Button('delete')
956          .height('5%')
957          .onClick(() => {
958            // 先点击update再点击delete
959            let newSection: SectionOptions = {
960              itemsCount: 2,
961              crossCount: 2,
962              columnsGap: 5,
963              rowsGap: 10,
964              margin: this.sectionMargin,
965              onGetItemMainSizeByIndex: (index: number) => {
966                return this.itemHeightArray[index % 100];
967              }
968            }
969            this.dataSource.deleteItem(this.oneColumnSection.itemsCount);
970            this.dataSource.deleteItem(this.oneColumnSection.itemsCount);
971            this.dataSource.deleteItem(this.oneColumnSection.itemsCount);
972            this.dataSource.deleteItem(this.oneColumnSection.itemsCount);
973            this.sections.update(1, newSection);
974          })
975          .margin({ top: 10, left: 20 })
976        Button('values')
977          .height('5%')
978          .onClick(() => {
979            const sections: Array<SectionOptions> = this.sections.values();
980            for (const value of sections) {
981              console.log(JSON.stringify(value));
982            }
983            console.info('count:' + this.sections.length());
984          })
985          .margin({ top: 10, left: 20 })
986      }.margin({ bottom: 20 })
987
988      WaterFlow({ scroller: this.scroller, sections: this.sections }) {
989        LazyForEach(this.dataSource, (item: number) => {
990          FlowItem() {
991            ReusableFlowItem({ item: item })
992          }
993          .width('100%')
994          // 以onGetItemMainSizeByIndex为准
995          // .height(this.itemHeightArray[item % 100])
996          .backgroundColor(this.colors[item % 5])
997        }, (item: string) => item)
998      }
999      .columnsTemplate('1fr 1fr') // 瀑布流使用sections参数时该属性无效
1000      .columnsGap(10)
1001      .rowsGap(5)
1002      .backgroundColor(0xFAEEE0)
1003      .width('100%')
1004      .height('100%')
1005      .layoutWeight(1)
1006      .onScrollIndex((first: number, last: number) => {
1007        // 即将触底时提前增加数据
1008        if (last + 20 >= this.dataSource.totalCount()) {
1009          for (let i = 0; i < 100; i++) {
1010            this.dataSource.addLastItem();
1011          }
1012          // 更新数据源后同步更新sections,修改最后一个section的FlowItem数量
1013          const sections: Array<SectionOptions> = this.sections.values();
1014          let newSection: SectionOptions = sections[this.sections.length() - 1];
1015          newSection.itemsCount += 100;
1016          this.sections.update(-1, newSection);
1017        }
1018      })
1019    }
1020  }
1021}
1022```
1023
1024![waterflowSections.png](figures/waterflowSections.png)
1025
1026### 示例4(双指缩放改变列数)
1027该示例通过[priorityGesture](ts-gesture-settings.md)和[PinchGesture](ts-basic-gestures-pinchgesture.md)实现了双指缩放改变列数效果。
1028
1029<!--code_no_check-->
1030```ts
1031// Index.ets
1032import { WaterFlowDataSource } from './WaterFlowDataSource';
1033
1034@Reusable
1035@Component
1036struct ReusableFlowItem {
1037  @State item: number = 0;
1038
1039  // 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容
1040  aboutToReuse(params: Record<string, number>) {
1041    this.item = params.item;
1042    console.info('Reuse item:' + this.item);
1043  }
1044
1045  aboutToAppear() {
1046    console.info('item:' + this.item);
1047  }
1048
1049  build() {
1050    Column() {
1051      Text("N" + this.item).fontSize(12).height('16')
1052      Image('res/waterFlow (' + this.item % 5 + ').JPG')
1053        .objectFit(ImageFit.Fill)
1054        .width('100%')
1055        .layoutWeight(1)
1056    }
1057  }
1058}
1059
1060@Entry
1061@Component
1062struct WaterFlowDemo {
1063  minSize: number = 80;
1064  maxSize: number = 180;
1065  colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F];
1066  @State columns: number = 2;
1067  dataSource: WaterFlowDataSource = new WaterFlowDataSource();
1068  private itemWidthArray: number[] = [];
1069  private itemHeightArray: number[] = [];
1070
1071  // 计算FlowItem宽/高
1072  getSize() {
1073    let ret = Math.floor(Math.random() * this.maxSize);
1074    return (ret > this.minSize ? ret : this.minSize);
1075  }
1076
1077  // 设置FlowItem的宽/高数组
1078  setItemSizeArray() {
1079    for (let i = 0; i < 100; i++) {
1080      this.itemWidthArray.push(this.getSize());
1081      this.itemHeightArray.push(this.getSize());
1082    }
1083  }
1084
1085  aboutToAppear() {
1086    let lastCount = AppStorage.get<number>('columnsCount');
1087    if (typeof lastCount != 'undefined') {
1088      this.columns = lastCount;
1089    }
1090    this.setItemSizeArray();
1091  }
1092
1093  build() {
1094    Column({ space: 2 }) {
1095      Row() {
1096        Text('双指缩放改变列数')
1097          .height('5%')
1098          .margin({ top: 10, left: 20 })
1099      }
1100
1101      WaterFlow() {
1102        LazyForEach(this.dataSource, (item: number) => {
1103          FlowItem() {
1104            ReusableFlowItem({ item: item })
1105          }
1106          .width('100%')
1107          .height(this.itemHeightArray[item % 100])
1108          .backgroundColor(this.colors[item % 5])
1109        }, (item: string) => item)
1110      }
1111      .columnsTemplate('1fr '.repeat(this.columns))
1112      .columnsGap(10)
1113      .rowsGap(5)
1114      .backgroundColor(0xFAEEE0)
1115      .width('100%')
1116      .height('100%')
1117      .layoutWeight(1)
1118      // 切换列数item位置重排动画
1119      .animation({
1120        duration: 300,
1121        curve: Curve.Smooth
1122      })
1123      .priorityGesture(
1124        PinchGesture()
1125          .onActionEnd((event: GestureEvent) => {
1126            console.info('end scale:' + event.scale);
1127            // 手指分开,减少列数以放大item,触发阈值可以自定义,示例为2
1128            if (event.scale > 2) {
1129              this.columns--;
1130            } else if (event.scale < 0.6) {
1131              this.columns++;
1132            }
1133            // 可以根据设备屏幕宽度设定最大和最小列数,此处以最小1列最大4列为例
1134            this.columns = Math.min(4, Math.max(1, this.columns));
1135            AppStorage.setOrCreate<number>('columnsCount', this.columns);
1136          })
1137      )
1138    }
1139  }
1140}
1141```
1142
1143![pinch](figures/waterflow-pinch.gif)
1144
1145### 示例5(设置边缘渐隐效果)
1146该示例通过[fadingEdge](ts-container-scrollable-common.md#fadingedge14)实现了WaterFlow组件开启边缘渐隐效果,并通过fadingEdgeLength参数设置边缘渐隐长度。
1147
1148<!--code_no_check-->
1149```ts
1150// Index.ets
1151import { LengthMetrics } from '@kit.ArkUI';
1152import { WaterFlowDataSource } from './WaterFlowDataSource';
1153@Entry
1154@Component
1155struct WaterFlowDemo {
1156  @State minSize: number = 80;
1157  @State maxSize: number = 180;
1158  @State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F];
1159  dataSource: WaterFlowDataSource = new WaterFlowDataSource();
1160  scroller: Scroller = new Scroller();
1161  private itemWidthArray: number[] = [];
1162  private itemHeightArray: number[] = [];
1163
1164  // 计算FlowItem宽/高
1165  getSize() {
1166    let ret = Math.floor(Math.random() * this.maxSize);
1167    return (ret > this.minSize ? ret : this.minSize);
1168  }
1169
1170  // 设置FlowItem宽/高数组
1171  setItemSizeArray() {
1172    for (let i = 0; i < 100; i++) {
1173      this.itemWidthArray.push(this.getSize());
1174      this.itemHeightArray.push(this.getSize());
1175    }
1176  }
1177
1178  aboutToAppear() {
1179    this.setItemSizeArray();
1180  }
1181
1182  build() {
1183    Column({ space: 2 }) {
1184
1185      WaterFlow({ scroller:this.scroller }) {
1186        LazyForEach(this.dataSource, (item: number) => {
1187          FlowItem() {
1188            Column() {
1189              Text("N" + item).fontSize(12).height('16')
1190            }
1191          }
1192          .width('100%')
1193          .height(this.itemHeightArray[item % 100])
1194          .backgroundColor(this.colors[item % 5])
1195        }, (item: string) => item)
1196      }
1197      .columnsTemplate('repeat(auto-fill,80)')
1198      .columnsGap(10)
1199      .rowsGap(5)
1200      .height('90%')
1201      .scrollBar(BarState.On)
1202      .fadingEdge(true,{fadingEdgeLength:LengthMetrics.vp(80)})
1203
1204    }
1205  }
1206}
1207```
1208
1209![fadingEdge_waterFlow](figures/fadingEdge_waterFlow.gif)