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 23WaterFlow(options?: WaterFlowOptions) 24 25**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 26 27**系统能力:** SystemCapability.ArkUI.ArkUI.Full 28 29**参数:** 30 31| 参数名 | 类型 | 必填 | 说明 | 32| -------- | -------- | -------- | -------- | 33| options | [WaterFlowOptions](#waterflowoptions对象说明)| 否 | 瀑布流组件参数。 | 34 35 36## WaterFlowOptions对象说明 37 38**系统能力:** SystemCapability.ArkUI.ArkUI.Full 39 40| 名称 | 类型 | 必填 | 说明 | 41| ---------- | ----------------------------------------------- | ------ | -------------------------------------------- | 42| footer | [CustomBuilder](ts-types.md#custombuilder8) | 否 | 设置WaterFlow尾部组件。<br/>**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 | 43| 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开始,该接口支持在原子化服务中使用。 | 44| sections<sup>12+</sup> | [WaterFlowSections](#waterflowsections12) | 否 | 设置FlowItem分组,实现同一个瀑布流组件内部各分组使用不同列数混合布局。<br/>**说明:** <br/>1. 使用分组混合布局时会忽略columnsTemplate和rowsTemplate属性。<br/>2. 使用分组混合布局时不支持单独设置footer,可以使用最后一个分组作为尾部组件。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | 45| layoutMode<sup>12+</sup> |[WaterFlowLayoutMode](#waterflowlayoutmode12枚举说明) | 否 | 设置WaterFlow的布局模式,根据使用场景选择更切合的模式。<br/>**说明:** <br/>默认值:[ALWAYS_TOP_DOWN](#waterflowlayoutmode12枚举说明)。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 46 47 48## WaterFlowSections<sup>12+</sup> 49 50瀑布流分组信息。 51 52> **说明:** 53> 54> 使用splice、push、update修改分组信息后需要保证所有分组子节点总数与瀑布流实际子节点总数一致,否则会出现瀑布流因为不能正常布局而无法滑动的问题。 55 56### constructor 57 58constructor() 59 60创建一个瀑布流分组。 61 62**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 63 64**系统能力:** SystemCapability.ArkUI.ArkUI.Full 65 66### splice<sup>12+</sup> 67 68splice(start: number, deleteCount?: number, sections?: Array\<SectionOptions\>): boolean 69 70移除或者替换已存在的分组和/或添加新分组。 71 72**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 73 74**系统能力:** SystemCapability.ArkUI.ArkUI.Full 75 76**参数:** 77 78| 参数名 | 类型 | 必填 | 说明 | 79| ---- | ----------------------------- | ---- | -------------------- | 80| start | number | 是 | 从0开始计算的索引,会转换为整数,表示要开始改变分组的位置。<br/>**说明:** <br/>1. 如果索引是负数,则从末尾开始计算,使用`start + WaterFlowSections.length()`。<br/>2. 如果 `start < -WaterFlowSections.length()`,则使用0。<br/>3. 如果 `start >= WaterFlowSections.length()`,则在最后添加新分组。 | 81| deleteCount | number | 否 | 表示要从start开始删除的分组数量。<br/>**说明:** <br/>1. 如果省略了deleteCount,或者其值大于或等于由start指定的位置到WaterFlowSections末尾的分组数量,那么从start到WaterFlowSections末尾的所有分组将被删除。<br/>2. 如果deleteCount是0或者负数,则不会删除任何分组。 | 82| sections | Array<[SectionOptions](#sectionoptions12对象说明)> | 否 | 表示要从start开始加入的分组。如果不指定,`splice()`将只从瀑布流中删除分组。 | 83 84**返回值:** 85 86| 类型 | 说明 | 87| ------------------------------------------------------------ | ------------------------------------------------------------ | 88| boolean | 分组是否修改成功,要加入的分组中有任意分组的itemsCount不是正整数时返回false。 | 89 90 91### push<sup>12+</sup> 92 93push(section: SectionOptions): boolean 94 95将指定分组添加到瀑布流末尾。 96 97**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 98 99**系统能力:** SystemCapability.ArkUI.ArkUI.Full 100 101**参数:** 102 103| 参数名 | 类型 | 必填 | 说明 | 104| ---- | ----------------------------- | ---- | -------------------- | 105| section | [SectionOptions](#sectionoptions12对象说明) | 是 | 添加到瀑布流末尾的分组。 | 106 107**返回值:** 108 109| 类型 | 说明 | 110| ------------------------------------------------------------ | ------------------------------------------------------------ | 111| boolean | 分组是否添加成功,新分组的itemsCount不是正整数时返回false。 | 112 113### update<sup>12+</sup> 114 115update(sectionIndex: number, section: SectionOptions): boolean 116 117修改指定索引分组的配置信息。 118 119**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 120 121**系统能力:** SystemCapability.ArkUI.ArkUI.Full 122 123**参数:** 124 125| 参数名 | 类型 | 必填 | 说明 | 126| ---- | ----------------------------- | ---- | -------------------- | 127| sectionIndex | number | 是 | 从0开始计算的索引,会转换为整数,表示要修改的分组的位置。<br/>**说明:** <br/>1. 如果索引是负数,则从末尾开始计算,使用`sectionIndex + WaterFlowSections.length()`。<br/>2. 如果`sectionIndex < -WaterFlowSections.length()`,则使用0。<br/>3. 如果`sectionIndex >= WaterFlowSections.length()`,则在最后添加新分组。 | 128| section | [SectionOptions](#sectionoptions12对象说明) | 是 | 新的分组信息。 | 129 130**返回值:** 131 132| 类型 | 说明 | 133| ------------------------------------------------------------ | ------------------------------------------------------------ | 134| boolean | 分组是否更新成功,新分组的itemsCount不是正整数时返回false。 | 135 136### values<sup>12+</sup> 137 138values(): Array\<SectionOptions\> 139 140获取瀑布流中所有分组配置信息。 141 142**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 143 144**系统能力:** SystemCapability.ArkUI.ArkUI.Full 145 146**返回值:** 147 148| 类型 | 说明 | 149| ------------------------------------------------------------ | ------------------------------------------------------------ | 150| Array<[SectionOptions](#sectionoptions12对象说明)> | 瀑布流中所有分组配置信息。 | 151 152### length<sup>12+</sup> 153 154length(): number 155 156获取瀑布流中分组数量。 157 158**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 159 160**系统能力:** SystemCapability.ArkUI.ArkUI.Full 161 162**返回值:** 163 164| 类型 | 说明 | 165| ------------------------------------------------------------ | ------------------------------------------------------------ | 166| number | 瀑布流中分组数量。 | 167 168## SectionOptions<sup>12+</sup>对象说明 169 170FlowItem分组配置信息。 171 172**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 173 174**系统能力:** SystemCapability.ArkUI.ArkUI.Full 175 176| 名称 | 类型 | 必填 | 说明 | 177|------|-----|-----|-----| 178| itemsCount | number | 是 | 分组中FlowItem数量,必须是正整数。若splice、push、update方法收到的分组中有分组的itemsCount小于0,则不会执行该方法。 | 179| crossCount | number | 否 | 纵向布局时为列数,横向布局时为行数,默认值:1。小于1的按默认值处理。 | 180| columnsGap | [Dimension](ts-types.md#dimension10) | 否 | 该分组的列间距,不设置时使用瀑布流的columnsGap,设置非法值时使用0vp。 | 181| rowsGap | [Dimension](ts-types.md#dimension10) | 否 | 该分组的行间距,不设置时使用瀑布流的rowsGap,设置非法值时使用0vp。 | 182| margin | [Margin](ts-types.md#margin) \| [Dimension](ts-types.md#dimension10) | 否 | 该分组的外边距参数为Length类型时,四个方向外边距同时生效。<br>默认值:0<br>单位:vp<br>margin设置百分比时,上下左右外边距均以瀑布流的width作为基础值。 | 183| onGetItemMainSizeByIndex | [GetItemMainSizeByIndex](#getitemmainsizebyindex12) | 否 | 瀑布流组件布局过程中获取指定index的FlowItem的主轴大小,纵向瀑布流时为高度,横向瀑布流时为宽度,单位vp。<br/>**说明:** <br/>1. 同时使用onGetItemMainSizeByIndex和FlowItem的宽高属性时,主轴大小以onGetItemMainSizeByIndex返回结果为准,onGetItemMainSizeByIndex会覆盖FlowItem的主轴长度。<br/>2. 使用onGetItemMainSizeByIndex可以提高瀑布流跳转到指定位置或index时的效率,避免混用设置onGetItemMainSizeByIndex和未设置的分组,会导致布局异常。<br/>3. onGetItemMainSizeByIndex返回负数时FlowItem高度为0。 | 184 185 186## GetItemMainSizeByIndex<sup>12+</sup> 187 188type GetItemMainSizeByIndex = (index: number) => number 189 190根据index获取指定Item的主轴大小。 191 192**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 193 194**系统能力:** SystemCapability.ArkUI.ArkUI.Full 195 196**参数:** 197 198| 参数名 | 类型 | 必填 | 说明 | 199| ---- | ----------------------------- | ---- | -------------------- | 200| index | number | 是 | FlowItem在WaterFlow中的索引。 | 201 202**返回值:** 203 204| 类型 | 说明 | 205| ------------------------------------------------------------ | ------------------------------------------------------------ | 206| number | 指定index的FlowItem的主轴大小,纵向瀑布流时为高度,横向瀑布流时为宽度,单位vp。 | 207 208## WaterFlowLayoutMode<sup>12+</sup>枚举说明 209 210**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 211 212**系统能力:** SystemCapability.ArkUI.ArkUI.Full 213 214| 名称 | 值 | 说明 | 215| ------ | ------ | -------------------- | 216| ALWAYS_TOP_DOWN | 0 | 默认的从上到下的布局模式。视窗内的FlowItem依赖视窗上方所有FlowItem的布局信息。因此跳转或切换列数时,需要计算出上方所有的FlowItem的布局信息。 | 217| 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)事件。 | 218 219 220## 属性 221 222除支持[通用属性](ts-universal-attributes-size.md)和[滚动组件通用属性](ts-container-scrollable-common.md#属性)外,还支持以下属性: 223 224### columnsTemplate 225 226columnsTemplate(value: string) 227 228设置当前瀑布流组件布局列的数量,不设置时默认1列。 229 230例如, '1fr 1fr 2fr' 是将父组件分3列,将父组件允许的宽分为4等份,第一列占1份,第二列占1份,第三列占2份。 231 232可使用columnsTemplate('repeat(auto-fill,track-size)')根据给定的列宽track-size自动计算列数,其中repeat、auto-fill为关键字,track-size为可设置的宽度,支持的单位包括px、vp、%或有效数字,默认单位为vp,使用方法参见示例2。 233 234**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 235 236**系统能力:** SystemCapability.ArkUI.ArkUI.Full 237 238**参数:** 239 240| 参数名 | 类型 | 必填 | 说明 | 241| ------ | ------ | ---- | ---------------------------------------------- | 242| value | string | 是 | 当前瀑布流组件布局列的数量。<br/>默认值:'1fr' | 243 244### rowsTemplate 245 246rowsTemplate(value: string) 247 248设置当前瀑布流组件布局行的数量,不设置时默认1行。 249 250例如, '1fr 1fr 2fr'是将父组件分三行,将父组件允许的高分为4等份,第一行占1份,第二行占一份,第三行占2份。 251 252可使用rowsTemplate('repeat(auto-fill,track-size)')根据给定的行高track-size自动计算行数,其中repeat、auto-fill为关键字,track-size为可设置的高度,支持的单位包括px、vp、%或有效数字,默认单位为vp。 253 254**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 255 256**系统能力:** SystemCapability.ArkUI.ArkUI.Full 257 258**参数:** 259 260| 参数名 | 类型 | 必填 | 说明 | 261| ------ | ------ | ---- | ---------------------------------------------- | 262| value | string | 是 | 当前瀑布流组件布局行的数量。<br/>默认值:'1fr' | 263 264### itemConstraintSize 265 266itemConstraintSize(value: ConstraintSizeOptions) 267 268设置约束尺寸,子组件布局时,进行尺寸范围限制。 269 270**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 271 272**系统能力:** SystemCapability.ArkUI.ArkUI.Full 273 274**参数:** 275 276| 参数名 | 类型 | 必填 | 说明 | 277| ------ | ---------------------------------------------------------- | ---- | ---------- | 278| 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)相同。| 279 280### columnsGap 281 282columnsGap(value: Length) 283 284设置列与列的间距。 285 286**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 287 288**系统能力:** SystemCapability.ArkUI.ArkUI.Full 289 290**参数:** 291 292| 参数名 | 类型 | 必填 | 说明 | 293| ------ | ---------------------------- | ---- | ----------------------------- | 294| value | [Length](ts-types.md#length) | 是 | 列与列的间距。 <br/>默认值:0 | 295 296### rowsGap 297 298rowsGap(value: Length) 299 300设置行与行的间距。 301 302**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 303 304**系统能力:** SystemCapability.ArkUI.ArkUI.Full 305 306**参数:** 307 308| 参数名 | 类型 | 必填 | 说明 | 309| ------ | ---------------------------- | ---- | ----------------------------- | 310| value | [Length](ts-types.md#length) | 是 | 行与行的间距。 <br/>默认值:0 | 311 312### layoutDirection 313 314layoutDirection(value: FlexDirection) 315 316设置布局的主轴方向。 317 318**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 319 320**系统能力:** SystemCapability.ArkUI.ArkUI.Full 321 322**参数:** 323 324| 参数名 | 类型 | 必填 | 说明 | 325| ------ | --------------------------------------------------- | ---- | ------------------------------------------------- | 326| value | [FlexDirection](ts-appendix-enums.md#flexdirection) | 是 | 布局的主轴方向。<br/>默认值:FlexDirection.Column | 327 328layoutDirection优先级高于rowsTemplate和columnsTemplate。根据layoutDirection设置情况,分为以下三种设置模式: 329 330- layoutDirection设置纵向布局(FlexDirection.Column 或 FlexDirection.ColumnReverse) 331 332 此时columnsTemplate有效(如果未设置,取默认值)。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件纵向布局,辅轴均分成横向2列。 333 334- layoutDirection设置横向布局(FlexDirection.Row 或 FlexDirection.RowReverse) 335 336 此时rowsTemplate有效(如果未设置,取默认值)。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件横向布局,辅轴均分成纵向3列。 337 338- layoutDirection未设置布局方向 339 340 布局方向为layoutDirection的默认值:FlexDirection.Column,此时columnsTemplate有效。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件纵向布局,辅轴均分成横向2列。 341 342### enableScrollInteraction<sup>10+</sup> 343 344enableScrollInteraction(value: boolean) 345 346设置是否支持滚动手势,当设置为false时,无法通过手指或者鼠标滚动,但不影响控制器的滚动接口。 347 348**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 349 350**系统能力:** SystemCapability.ArkUI.ArkUI.Full 351 352**参数:** 353 354| 参数名 | 类型 | 必填 | 说明 | 355| ------ | ------- | ---- | ----------------------------------- | 356| value | boolean | 是 | 是否支持滚动手势。<br/>默认值:true | 357 358### nestedScroll<sup>10+</sup> 359 360nestedScroll(value: NestedScrollOptions) 361 362设置向前向后两个方向上的嵌套滚动模式,实现与父组件的滚动联动。 363 364**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 365 366**系统能力:** SystemCapability.ArkUI.ArkUI.Full 367 368**参数:** 369 370| 参数名 | 类型 | 必填 | 说明 | 371| ------ | ------------------------------------------------------------ | ---- | -------------- | 372| value | [NestedScrollOptions](ts-container-scrollable-common.md#nestedscrolloptions10对象说明) | 是 | 嵌套滚动选项。 | 373 374### friction<sup>10+</sup> 375 376friction(value: number | Resource) 377 378设置摩擦系数,手动划动滚动区域时生效,只对惯性滚动过程有影响,对惯性滚动过程中的链式效果有间接影响。设置为小于等于0的值时,按默认值处理。 379 380**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 381 382**系统能力:** SystemCapability.ArkUI.ArkUI.Full 383 384**参数:** 385 386| 参数名 | 类型 | 必填 | 说明 | 387| ------ | ---------------------------------------------------- | ---- | --------------------------------------------------------- | 388| value | number \| [Resource](ts-types.md#resource) | 是 | 摩擦系数。<br/>默认值:非可穿戴设备为0.6,可穿戴设备为0.9。<br/>从API version 11开始,非可穿戴设备默认值为0.7。<br/>从API version 12开始,非可穿戴设备默认值为0.75。 | 389 390### cachedCount<sup>11+</sup> 391 392cachedCount(value: number) 393 394设置预加载的FlowItem的数量,只在LazyForEach中生效。设置该属性后会缓存cachedCount个FlowItem。[LazyForEach](../../../quick-start/arkts-rendering-control-lazyforeach.md)超出显示和缓存范围的FlowItem会被释放。设置为小于0的值时,按默认值显示。 395 396**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 397 398**系统能力:** SystemCapability.ArkUI.ArkUI.Full 399 400**参数:** 401 402| 参数名 | 类型 | 必填 | 说明 | 403| ------ | ------ | ---- | ------------------------------------------------------------ | 404| value | number | 是 | 预加载的FlowItem的数量。 <br/> 默认值:根据屏幕内显示的节点个数设置,最大值为16。 | 405 406### cachedCount<sup>14+</sup> 407 408cachedCount(count: number, show: boolean) 409 410设置预加载的FlowItem数量,并配置是否显示预加载节点。 411 412配合[裁剪](ts-universal-attributes-sharp-clipping.md#clip12)或[内容裁剪](ts-container-scrollable-common.md#clipcontent14)属性可以显示出预加载节点。 413 414[LazyForEach](../../../quick-start/arkts-rendering-control-lazyforeach.md)和开启了virtualScroll开关的[Repeat](../../../quick-start/arkts-new-rendering-control-repeat.md)超出显示和缓存范围的FlowItem会被释放。 415 416**原子化服务API:** 从API version 14开始,该接口支持在原子化服务中使用。 417 418**系统能力:** SystemCapability.ArkUI.ArkUI.Full 419 420**参数:** 421 422| 参数名 | 类型 | 必填 | 说明 | 423| ------ | ------ | ---- | ---------------------------------------- | 424| count | number | 是 | 预加载的FlowItem的数量。 <br/> 默认值:根据屏幕内显示的节点个数设置,最大值为16。 | 425| show | boolean | 是 | 被预加载的FlowItem是否需要显示。 <br/> 默认值:false | 426 427## 事件 428 429除支持[通用事件](ts-universal-events-click.md)和[滚动组件通用事件](ts-container-scrollable-common.md#事件)外,还支持以下事件: 430 431### onReachStart 432 433onReachStart(event: () => void) 434 435瀑布流组件到达起始位置时触发。 436 437**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 438 439**系统能力:** SystemCapability.ArkUI.ArkUI.Full 440 441### onReachEnd 442 443onReachEnd(event: () => void) 444 445瀑布流组件到底末尾位置时触发。 446 447**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 448 449**系统能力:** SystemCapability.ArkUI.ArkUI.Full 450 451### onScrollFrameBegin<sup>10+</sup> 452 453onScrollFrameBegin(event: (offset: number, state: ScrollState) => { offsetRemain: number; }) 454 455瀑布流开始滑动时触发,事件参数传入即将发生的滑动量,事件处理函数中可根据应用场景计算实际需要的滑动量并作为事件处理函数的返回值返回,瀑布流将按照返回值的实际滑动量进行滑动。 456 457触发该事件的条件:手指拖动WaterFlow、WaterFlow惯性划动时每帧开始时触发;WaterFlow超出边缘回弹、使用滚动控制器和拖动滚动条的滚动不会触发。 458 459**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 460 461**系统能力:** SystemCapability.ArkUI.ArkUI.Full 462 463**参数:** 464 465| 参数名 | 类型 | 必填 | 说明 | 466| ------ | ------------------------------------------------------- | ---- | -------------------------- | 467| offset | number | 是 | 即将发生的滑动量,单位vp。 | 468| state | [ScrollState](ts-container-list.md#scrollstate枚举说明) | 是 | 当前滑动状态。 | 469 470**返回值:** 471 472| 类型 | 说明 | 473| ------------------------ | -------------------- | 474| { offsetRemain: number } | 实际滑动量,单位vp。 | 475 476### onScrollIndex<sup>11+</sup> 477 478onScrollIndex(event: (first: number, last: number) => void) 479 480当前瀑布流显示的起始位置/终止位置的子组件发生变化时触发。瀑布流初始化时会触发一次。 481 482瀑布流显示区域上第一个子组件/最后一个组件的索引值有变化就会触发。 483 484**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 485 486**系统能力:** SystemCapability.ArkUI.ArkUI.Full 487 488**参数:** 489 490| 参数名 | 类型 | 必填 | 说明 | 491| ------ | ------ | ---- | ------------------------------------- | 492| first | number | 是 | 当前显示的瀑布流起始位置的索引值。 | 493| last | number | 是 | 当前显示的瀑布流终止位置的索引值。 | 494 495## 示例 496 497### 示例1(使用基本瀑布流) 498该示例展示了WaterFlow组件数据加载处理、属性设置和事件回调等基本使用场景。 499```ts 500// WaterFlowDataSource.ets 501 502// 实现IDataSource接口的对象,用于瀑布流组件加载数据 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 // 获取索引对应的数据 514 public getData(index: number): number { 515 return this.dataArray[index] 516 } 517 518 // 通知控制器数据重新加载 519 notifyDataReload(): void { 520 this.listeners.forEach(listener => { 521 listener.onDataReloaded() 522 }) 523 } 524 525 // 通知控制器数据增加 526 notifyDataAdd(index: number): void { 527 this.listeners.forEach(listener => { 528 listener.onDataAdd(index) 529 }) 530 } 531 532 // 通知控制器数据变化 533 notifyDataChange(index: number): void { 534 this.listeners.forEach(listener => { 535 listener.onDataChange(index) 536 }) 537 } 538 539 // 通知控制器数据删除 540 notifyDataDelete(index: number): void { 541 this.listeners.forEach(listener => { 542 listener.onDataDelete(index) 543 }) 544 } 545 546 // 通知控制器数据位置变化 547 notifyDataMove(from: number, to: number): void { 548 this.listeners.forEach(listener => { 549 listener.onDataMove(from, to) 550 }) 551 } 552 553 //通知控制器数据批量修改 554 notifyDatasetChange(operations: DataOperation[]): void { 555 this.listeners.forEach(listener => { 556 listener.onDatasetChange(operations); 557 }) 558 } 559 560 // 获取数据总数 561 public totalCount(): number { 562 return this.dataArray.length 563 } 564 565 // 注册改变数据的控制器 566 registerDataChangeListener(listener: DataChangeListener): void { 567 if (this.listeners.indexOf(listener) < 0) { 568 this.listeners.push(listener) 569 } 570 } 571 572 // 注销改变数据的控制器 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 // 增加数据 581 public add1stItem(): void { 582 this.dataArray.splice(0, 0, this.dataArray.length) 583 this.notifyDataAdd(0) 584 } 585 586 // 在数据尾部增加一个元素 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 // 在指定索引位置增加一个元素 593 public addItem(index: number): void { 594 this.dataArray.splice(index, 0, this.dataArray.length) 595 this.notifyDataAdd(index) 596 } 597 598 // 删除第一个元素 599 public delete1stItem(): void { 600 this.dataArray.splice(0, 1) 601 this.notifyDataDelete(0) 602 } 603 604 // 删除第二个元素 605 public delete2ndItem(): void { 606 this.dataArray.splice(1, 1) 607 this.notifyDataDelete(1) 608 } 609 610 // 删除最后一个元素 611 public deleteLastItem(): void { 612 this.dataArray.splice(-1, 1) 613 this.notifyDataDelete(this.dataArray.length) 614 } 615 616 // 在指定索引位置删除一个元素 617 public deleteItem(index: number): void { 618 this.dataArray.splice(index, 1) 619 this.notifyDataDelete(index) 620 } 621 622 // 重新加载数据 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 // 计算FlowItem宽/高 648 getSize() { 649 let ret = Math.floor(Math.random() * this.maxSize) 650 return (ret > this.minSize ? ret : this.minSize) 651 } 652 653 // 设置FlowItem的宽/高数组 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 // 存在对应的jpg文件才会显示图片 686 Image('res/waterFlowTest(' + item % 5 + ').jpg') 687 .objectFit(ImageFit.Fill) 688 .width('100%') 689 .layoutWeight(1) 690 } 691 } 692 .onAppear(() => { 693 // 即将触底时提前增加数据 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 730 731### 示例2(自动计算列数) 732该示例通过auto-fill实现了自动计算列数的效果。 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 // 计算FlowItem宽/高 748 getSize() { 749 let ret = Math.floor(Math.random() * this.maxSize) 750 return (ret > this.minSize ? ret : this.minSize) 751 } 752 753 // 设置FlowItem宽/高数组 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 793 794 795### 示例3(使用分组) 796该示例展示了分组的初始化以及splice、push、update、values、length等接口的不同效果。 797如果配合状态管理V2使用,详情见:[WaterFlow与makeObserved](../../../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 // 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容 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 // 计算FlowItem高度 865 getSize() { 866 let ret = Math.floor(Math.random() * this.maxSize) 867 return (ret > this.minSize ? ret : this.minSize) 868 } 869 870 // 设置FlowItem的高度数组 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 // 初始化瀑布流分组信息 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 // 将所有分组替换成一个新分组,注意保证LazyForEach中数据数量和新分组itemsCount保持一致 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 // 在第二个分组增加4个FlowItem,注意保证LazyForEach中数据数量和所有分组itemsCount的和保持一致 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 // 先点击update再点击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 // 以onGetItemMainSizeByIndex为准 981 // .height(this.itemHeightArray[item % 100]) 982 .backgroundColor(this.colors[item % 5]) 983 }, (item: string) => item) 984 } 985 .columnsTemplate('1fr 1fr') // 瀑布流使用sections参数时该属性无效 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 // 即将触底时提前增加数据 994 if (last + 20 >= this.dataSource.totalCount()) { 995 for (let i = 0; i < 100; i++) { 996 this.dataSource.addLastItem() 997 } 998 // 更新数据源后同步更新sections,修改最后一个section的FlowItem数量 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 1011 1012### 示例4(双指缩放改变列数) 1013该示例通过[priorityGesture](ts-gesture-settings.md)和[PinchGesture](ts-basic-gestures-pinchgesture.md)实现了双指缩放改变列数效果。 1014```ts 1015// Index.ets 1016import { WaterFlowDataSource } from './WaterFlowDataSource' 1017 1018@Reusable 1019@Component 1020struct ReusableFlowItem { 1021 @State item: number = 0 1022 1023 // 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容 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 // 计算FlowItem宽/高 1056 getSize() { 1057 let ret = Math.floor(Math.random() * this.maxSize) 1058 return (ret > this.minSize ? ret : this.minSize) 1059 } 1060 1061 // 设置FlowItem的宽/高数组 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('双指缩放改变列数') 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 // 切换列数item位置重排动画 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 // 手指分开,减少列数以放大item,触发阈值可以自定义,示例为2 1112 if (event.scale > 2) { 1113 this.columns-- 1114 } else if (event.scale < 0.6) { 1115 this.columns++ 1116 } 1117 // 可以根据设备屏幕宽度设定最大和最小列数,此处以最小1列最大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 1128 1129### 示例5(设置边缘渐隐效果) 1130该示例通过[fadingEdge](ts-container-scrollable-common.md#fadingedge14)实现了WaterFlow组件开启边缘渐隐效果,并通过fadingEdgeLength参数设置边缘渐隐长度。 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 // 计算FlowItem宽/高 1147 getSize() { 1148 let ret = Math.floor(Math.random() * this.maxSize) 1149 return (ret > this.minSize ? ret : this.minSize) 1150 } 1151 1152 // 设置FlowItem宽/高数组 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 .scrollBar(BarState.On) 1184 .fadingEdge(true,{fadingEdgeLength:LengthMetrics.vp(80)}) 1185 1186 } 1187 } 1188} 1189``` 1190 1191