harmony 鸿蒙WaterFlow

  • 2022-12-13
  • 浏览 (547)

WaterFlow

The <WaterFlow> component is a container that consists of cells formed by rows and columns and arranges items of different sizes from top to bottom according to the preset rules.

NOTE

This component is supported since API version 9. Updates will be marked with a superscript to indicate their earliest API version.

Child Components

This component can contain the <FlowItem> child component.

NOTE

If the visibility attribute of a <FlowItem> is set to None, the component is not displayed in the container, but the gaps around the component are still effective.

APIs

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

Parameters

Name Type Mandatory Description
footer CustomBuilder No Footer of the <WaterFlow> component.
scroller Scroller No Controller, which can be bound to scrollable components.
The <WaterFlow> component supports only the scrollToIndex API of the <Scroller> component.

Attributes

In addition to the universal attributes, the following attributes are supported.

Name Type Description
columnsTemplate string Number of columns in the layout. If this attribute is not set, one column is used by default.
For example, ‘1fr 1fr 2fr’ indicates three columns, with the first column taking up 14 of the parent component’s full width, the second column 14, and the third column 24. This attribute supports auto-fill.
Default value: ‘1fr’
rowsTemplate string Number of rows in the layout. If this attribute is not set, one row is used by default.
For example, ‘1fr 1fr 2fr’ indicates three rows, with the first row taking up 14 of the parent component’s full height, the second row 14, and the third row 24. This attribute supports auto-fill.
Default value: ‘1fr’
itemConstraintSize ConstraintSizeOptions Size constraints of the child components during layout.
columnsGap Length Gap between columns.
Default value: 0
rowsGap Length Gap between rows.
Default value: 0
layoutDirection FlexDirection Main axis direction of the layout.
Default value: FlexDirection.Column
enableScrollInteraction10+ boolean Whether to support scroll gestures. When this attribute is set to false, scrolling by finger or mouse is not supported, but the scrolling controller API is not affected.
Default value: true
nestedScroll10+ NestedScrollOptions Nested scrolling options. You can set the nested scrolling mode in the forward and backward directions to implement scrolling linkage with the parent component.
friction10+ number |Resource Friction coefficient. It applies only to gestures in the scrolling area, and it affects only indirectly the scroll chaining during the inertial scrolling process.
Default value: 0.9 for wearable devices and 0.6 for non-wearable devices
NOTE
A value less than or equal to 0 evaluates to the default value.

The priority of layoutDirection is higher than that of rowsTemplate and columnsTemplate. Depending on the layoutDirection settings, there are three layout modes:

  • layoutDirection is set to FlexDirection.Column or FlexDirection.ColumnReverse

    In this case, columnsTemplate is valid. If it is not set, the default value is used. For example, if columnsTemplate is set to “1fr 1fr” and rowsTemplate “1fr 1fr 1fr”, child components are arranged in vertical layout, with the cross axis equally divided into two columns.

  • layoutDirection set to FlexDirection.Row or FlexDirection.RowReverse

    In this case, rowsTemplate is valid. If it is not set, the default value is used. For example, if columnsTemplate is set to “1fr 1fr” and rowsTemplate “1fr 1fr 1fr”, child components are arranged in horizontal layout, with the cross axis equally divided into three columns.

  • layoutDirection is not set

    In this case, the default value of layoutDirection is used, which is FlexDirection.Column, and columnsTemplate is valid. For example, if columnsTemplate is set to “1fr 1fr” and rowsTemplate “1fr 1fr 1fr”, child components are arranged in vertical layout, with the cross axis equally divided into two columns.

Events

In addition to the universal events, the following events are supported.

Name Description
onReachStart(event: () => void) Triggered when the component reaches the start.
onReachEnd(event: () => void) Triggered when the component reaches the end position.
onScrollFrameBegin10+(event: (offset: number, state: ScrollState) => { offsetRemain }) Triggered when the component starts to scroll. The input parameters indicate the amount by which the component will scroll. The event handler then works out the amount by which the component needs to scroll based on the real-world situation and returns the result.
- offset: amount to scroll by, in vp.
- state: current scrolling state.
- offsetRemain: actual amount by which the component scrolls, in vp.
This event is triggered when the user starts dragging the component or the component starts inertial scrolling. This event is not triggered when the component rebounds or the scrolling controller is used.

auto-fill

The columnsTemplate and rowsTemplate attributes supports auto-fill in the following format:

repeat(auto-fill, track-size)

Where, repeat and auto-fill are keywords, and track-size indicates the row height or column width. The supported units include px, vp, %, and digits. The value of track-size must contain at least one valid row height or column width.

Example

// WaterFlowDataSource.ets

// Object that implements the IDataSource API, which is used by the <WaterFlow> component to load data.
export class WaterFlowDataSource implements IDataSource {
  private dataArray: number[] = []
  private listeners: DataChangeListener[] = []

  constructor() {
    for (let i = 0; i < 100; i++) {
      this.dataArray.push(i)
    }
  }

  // Obtain the data corresponding to the specified index.
  public getData(index: number): number {
    return this.dataArray[index]
  }

  // Notify the controller of data reloading.
  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded()
    })
  }

  // Notify the controller of data addition.
  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdded(index)
    })
  }

  // Notify the controller of data changes.
  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataChanged(index)
    })
  }

  // Notify the controller of data deletion.
  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataDeleted(index)
    })
  }

  // Notify the controller of the data location change.
  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMoved(from, to)
    })
  }

  // Obtain the total number of data records.
  public totalCount(): number {
    return this.dataArray.length
  }

  // Register the data change listener.
  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      this.listeners.push(listener)
    }
  }

  // Unregister the data change listener.
  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener)
    if (pos >= 0) {
      this.listeners.splice(pos, 1)
    }
  }

  // Add data.
  public Add1stItem(): void {
    this.dataArray.splice(0, 0, this.dataArray.length)
    this.notifyDataAdd(0)
  }

  // Add an item to the end of the data.
  public AddLastItem(): void {
    this.dataArray.splice(this.dataArray.length, 0, this.dataArray.length)
    this.notifyDataAdd(this.dataArray.length - 1)
  }

  // Add an item to the position corresponding to the specified index.
  public AddItem(index: number): void {
    this.dataArray.splice(index, 0, this.dataArray.length)
    this.notifyDataAdd(index)
  }

  // Delete the first item.
  public Delete1stItem(): void {
    this.dataArray.splice(0, 1)
    this.notifyDataDelete(0)
  }

  // Delete the second item.
  public Delete2ndItem(): void {
    this.dataArray.splice(1, 1)
    this.notifyDataDelete(1)
  }

  // Delete the last item.
  public DeleteLastItem(): void {
    this.dataArray.splice(-1, 1)
    this.notifyDataDelete(this.dataArray.length)
  }

  // Reload data.
  public Reload(): void {
    this.dataArray.splice(1, 1)
    this.dataArray.splice(3, 2)
    this.notifyDataReload()
  }
}
// WaterflowDemo.ets
import { WaterFlowDataSource } from './WaterFlowDataSource'

@Entry
@Component
struct WaterflowDemo {
  @State minSize: number = 50
  @State maxSize: number = 100
  @State fontSize: number = 24
  @State colors: number[] = [0xFFC0CB, 0xDA70D6, 0x6B8E23, 0x6A5ACD, 0x00FFFF, 0x00FF7F]
  scroller: Scroller = new Scroller()
  datasource: WaterFlowDataSource = new WaterFlowDataSource()
  private itemWidthArray: number[] = []
  private itemHeightArray: number[] = []

  // Calculate the width and height of a flow item.
  getSize() {
    let ret = Math.floor(Math.random() * this.maxSize)
    return (ret > this.minSize ? ret : this.minSize)
  }

  // Save the width and height of the flow item.
  getItemSizeArray() {
    for (let i = 0; i < 100; i++) {
      this.itemWidthArray.push(this.getSize())
      this.itemHeightArray.push(this.getSize())
    }
  }

  aboutToAppear() {
    this.getItemSizeArray()
  }

  @Builder
  itemFoot() {
    Column() {
      Text(`Footer`)
        .fontSize(10)
        .backgroundColor(Color.Red)
        .width(50)
        .height(50)
        .align(Alignment.Center)
        .margin({ top: 2 })
    }
  }

  build() {
    Column({ space: 2 }) {
      WaterFlow({ footer: () => { this.itemFoot() }, scroller: this.scroller }) {
        LazyForEach(this.datasource, (item: number) => {
          FlowItem() {
            Column() {
              Text("N" + item).fontSize(12).height('16')
              Image('res/waterFlowTest(' + item % 5 + ').jpg')
                .objectFit(ImageFit.Fill)
                .width('100%')
                .layoutWeight(1)
            }
          }
          .width('100%')
          .height(this.itemHeightArray[item])
          .backgroundColor(this.colors[item % 5])
        }, (item: string) => item)
      }
      .columnsTemplate("1fr 1fr 1fr 1fr")
      .itemConstraintSize({
        minWidth: 0,
        maxWidth: '100%',
        minHeight: 0,
        maxHeight: '100%'
      })
      .friction(0.6)
      .columnsGap(10)
      .rowsGap(5)
      .onReachStart(() => {
        console.info("onReachStart")
      })
      .onReachEnd(() => {
        console.info("onReachEnd")
      })
      .backgroundColor(0xFAEEE0)
      .width('100%')
      .height('80%')
      .layoutDirection(FlexDirection.Column)
    }
  }
}

en-us_image_WaterFlow.gif

你可能感兴趣的鸿蒙文章

harmony 鸿蒙ArkTS-based Declarative Development Paradigm

harmony 鸿蒙@ohos.multimedia.avCastPicker (AVCastPicker)

harmony 鸿蒙Property Animation

harmony 鸿蒙Enums

harmony 鸿蒙Blank

harmony 鸿蒙Button

harmony 鸿蒙CalendarPicker

harmony 鸿蒙Checkbox

harmony 鸿蒙CheckboxGroup

harmony 鸿蒙DataPanel

0  赞