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.Column 或 FlexDirection.ColumnReverse) 338 339 此时columnsTemplate有效(如果未设置,取默认值)。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件纵向布局,辅轴均分成横向2列。 340 341- layoutDirection设置横向布局(FlexDirection.Row 或 FlexDirection.RowReverse) 342 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 \| [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 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 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 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 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