瀑布流容器

2024-01-22 17:59 更新

瀑布流容器,由“行”和“列”分割的单元格所组成,通过容器自身的排列规则,将不同大小的“项目”自上而下,如瀑布般紧密布局。

说明

该组件从API Version 9开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

子组件

包含FlowItem子组件。

说明

WaterFlow子组件的visibility属性设置为None时不显示,但依然会占用子组件对应的网格。

接口

WaterFlow(options?: {footer?: CustomBuilder, scroller?: Scroller})

参数:

参数名

参数类型

必填

参数描述

footer

CustomBuilder

设置WaterFlow尾部组件。

scroller

Scroller

可滚动组件的控制器,与可滚动组件绑定。

目前瀑布流仅支持Scroller组件的scrollToIndex接口。

属性

除支持通用属性外,还支持以下属性:

名称

参数类型

描述

columnsTemplate

string

设置当前瀑布流组件布局列的数量,不设置时默认1列。

例如, '1fr 1fr 2fr' 是将父组件分3列,将父组件允许的宽分为4等份,第一列占1份,第二列占1份,第三列占2份。并支持auto-fill

默认值:'1fr'

rowsTemplate

string

设置当前瀑布流组件布局行的数量,不设置时默认1行。

例如, '1fr 1fr 2fr'是将父组件分三行,将父组件允许的高分为4等份,第一行占1份,第二行占一份,第三行占2份。并支持auto-fill

默认值:'1fr'

itemConstraintSize

ConstraintSizeOptions

设置约束尺寸,子组件布局时,进行尺寸范围限制。

columnsGap

Length

设置列与列的间距。

默认值:0

rowsGap

Length

设置行与行的间距。

默认值:0

layoutDirection

FlexDirection

设置布局的主轴方向。

默认值:FlexDirection.Column

layoutDirection优先级高于rowsTemplate和columnsTemplate。根据layoutDirection设置情况,分为以下三种设置模式:

  • layoutDirection设置纵向布局(FlexDirection.Column 或 FlexDirection.ColumnReverse)

    此时columnsTemplate有效(如果未设置,取默认值)。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件纵向布局,辅轴均分成横向2列。

  • layoutDirection设置横向布局(FlexDirection.Row 或 FlexDirection.RowReverse)

    此时rowsTemplate有效(如果未设置,取默认值)。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件横向布局,辅轴均分成纵向3列。

  • layoutDirection未设置布局方向

    布局方向为layoutDirection的默认值:FlexDirection.Column,此时columnsTemplate有效。例如columnsTemplate设置为"1fr 1fr"、rowsTemplate设置为"1fr 1fr 1fr"时,瀑布流组件纵向布局,辅轴均分成横向2列。

事件

除支持通用事件外,还支持以下事件:

名称

功能描述

onReachStart(event: () => void)

瀑布流组件到达起始位置时触发。

onReachEnd(event: () => void)

瀑布流组件到底末尾位置时触发。

auto-fill说明

WaterFlow的columnsTemplate、rowsTemplate属性的auto-fill仅支持以下格式:

  1. repeat(auto-fill, track-size)

其中repeat、auto-fill为关键字。track-size为行高或者列宽,支持的单位包括px、vp、%或有效数字,track-size至少包括一个有效行高或者列宽。

示例

  1. // WaterFlowDataSource.ets
  2. // 实现IDataSource接口的对象,用于瀑布流组件加载数据
  3. export class WaterFlowDataSource implements IDataSource {
  4. private dataArray: number[] = []
  5. private listeners: DataChangeListener[] = []
  6. constructor() {
  7. for (let i = 0; i < 100; i++) {
  8. this.dataArray.push(i)
  9. }
  10. }
  11. // 获取索引对应的数据
  12. public getData(index: number): any {
  13. return this.dataArray[index]
  14. }
  15. // 通知控制器数据重新加载
  16. notifyDataReload(): void {
  17. this.listeners.forEach(listener => {
  18. listener.onDataReloaded()
  19. })
  20. }
  21. // 通知控制器数据增加
  22. notifyDataAdd(index: number): void {
  23. this.listeners.forEach(listener => {
  24. listener.onDataAdded(index)
  25. })
  26. }
  27. // 通知控制器数据变化
  28. notifyDataChange(index: number): void {
  29. this.listeners.forEach(listener => {
  30. listener.onDataChanged(index)
  31. })
  32. }
  33. // 通知控制器数据删除
  34. notifyDataDelete(index: number): void {
  35. this.listeners.forEach(listener => {
  36. listener.onDataDeleted(index)
  37. })
  38. }
  39. // 通知控制器数据位置变化
  40. notifyDataMove(from: number, to: number): void {
  41. this.listeners.forEach(listener => {
  42. listener.onDataMoved(from, to)
  43. })
  44. }
  45. // 获取数据总数
  46. public totalCount(): number {
  47. return this.dataArray.length
  48. }
  49. // 注册改变数据的控制器
  50. registerDataChangeListener(listener: DataChangeListener): void {
  51. if (this.listeners.indexOf(listener) < 0) {
  52. this.listeners.push(listener)
  53. }
  54. }
  55. // 注销改变数据的控制器
  56. unregisterDataChangeListener(listener: DataChangeListener): void {
  57. const pos = this.listeners.indexOf(listener)
  58. if (pos >= 0) {
  59. this.listeners.splice(pos, 1)
  60. }
  61. }
  62. // 增加数据
  63. public Add1stItem(): void {
  64. this.dataArray.splice(0, 0, this.dataArray.length)
  65. this.notifyDataAdd(0)
  66. }
  67. // 在数据尾部增加一个元素
  68. public AddLastItem(): void {
  69. this.dataArray.splice(this.dataArray.length, 0, this.dataArray.length)
  70. this.notifyDataAdd(this.dataArray.length-1)
  71. }
  72. // 在指定索引位置增加一个元素
  73. public AddItem(index: number): void {
  74. this.dataArray.splice(index, 0, this.dataArray.length)
  75. this.notifyDataAdd(index)
  76. }
  77. // 删除第一个元素
  78. public Delete1stItem(): void {
  79. this.dataArray.splice(0, 1)
  80. this.notifyDataDelete(0)
  81. }
  82. // 删除第二个元素
  83. public Delete2ndItem(): void {
  84. this.dataArray.splice(1, 1)
  85. this.notifyDataDelete(1)
  86. }
  87. // 删除最后一个元素
  88. public DeleteLastItem(): void {
  89. this.dataArray.splice(-1, 1)
  90. this.notifyDataDelete(this.dataArray.length)
  91. }
  92. // 重新加载数据
  93. public Reload(): void {
  94. this.dataArray.splice(1, 1)
  95. this.dataArray.splice(3, 2)
  96. this.notifyDataReload()
  97. }
  98. }
  1. // WaterflowDemo.ets
  2. import { WaterFlowDataSource } from './WaterFlowDataSource'
  3. @Entry
  4. @Component
  5. struct WaterflowDemo {
  6. @State minSize: number = 50
  7. @State maxSize: number = 100
  8. @State fontSize: number = 24
  9. @State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]
  10. scroller: Scroller = new Scroller()
  11. datasource: WaterFlowDataSource = new WaterFlowDataSource()
  12. private itemWidthArray: number[] = []
  13. private itemHeightArray: number[] = []
  14. // 计算flow item宽/高
  15. getSize() {
  16. let ret = Math.floor(Math.random() * this.maxSize)
  17. return (ret > this.minSize ? ret : this.minSize)
  18. }
  19. // 保存flow item宽/高
  20. getItemSizeArray() {
  21. for (let i = 0; i < 100; i++) {
  22. this.itemWidthArray.push(this.getSize())
  23. this.itemHeightArray.push(this.getSize())
  24. }
  25. }
  26. aboutToAppear() {
  27. this.getItemSizeArray()
  28. }
  29. @Builder itemFoot() {
  30. Column() {
  31. Text(`Footer`)
  32. .fontSize(10)
  33. .backgroundColor(Color.Red)
  34. .width(50)
  35. .height(50)
  36. .align(Alignment.Center)
  37. .margin({ top: 2 })
  38. }
  39. }
  40. build() {
  41. Column({ space: 2 }) {
  42. WaterFlow({ footer: this.itemFoot.bind(this), scroller: this.scroller }) {
  43. LazyForEach(this.datasource, (item: number) => {
  44. FlowItem() {
  45. Column() {
  46. Text("N" + item).fontSize(12).height('16')
  47. Image('res/waterFlowTest(' + item % 5 + ').jpg')
  48. .objectFit(ImageFit.Fill)
  49. }
  50. }
  51. .width(this.itemWidthArray[item])
  52. .height(this.itemHeightArray[item])
  53. .backgroundColor(this.colors[item % 5])
  54. }, item => item)
  55. }
  56. .columnsTemplate("1fr 1fr 1fr 1fr")
  57. .itemConstraintSize({
  58. minWidth: 0,
  59. maxWidth: '100%',
  60. minHeight: 0,
  61. maxHeight: '100%'
  62. })
  63. .columnsGap(10)
  64. .rowsGap(5)
  65. .onReachStart(() => {
  66. console.info("onReachStart")
  67. })
  68. .onReachEnd(() => {
  69. console.info("onReachEnd")
  70. })
  71. .backgroundColor(0xFAEEE0)
  72. .width('100%')
  73. .height('80%')
  74. .layoutDirection(FlexDirection.Column)
  75. }
  76. }
  77. }

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号