Relative Layout, High-Performance List Optimization, Text Centering, Control Size Acquisition, Click Callback



This content originally appeared on DEV Community and was authored by kouwei qing

[Daily HarmonyOS Next Knowledge] Relative Layout, High-Performance List Optimization, Text Centering, Control Size Acquisition, Click Callback

1. How to set the height of HarmonyOS RelativeContainer to auto to adapt to the height of child controls?

The height of an item cannot be controlled, and it is desired to follow the height of child controls. How to achieve this?

When width is set to auto, if child components in the horizontal direction use the container as an anchor, auto will not take effect, and the same applies to the vertical direction. The code should not use container as an anchor. Refer to the documentation rules: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-relativecontainer-V5

Relative layout component for element alignment in complex scenarios:

  • Child components in the container are divided into horizontal and vertical directions:
    • Horizontal: left, middle, right (corresponding to HorizontalAlign.Start, Center, End).
    • Vertical: top, center, bottom (corresponding to VerticalAlign.Top, Center, Bottom).
  • Child components can use the container, guideline, barrier, or other child components as anchors:
    • Components in the relative layout container without an id can be displayed but cannot be used as anchors by other child components. The container will generate an id for them, whose pattern is not perceivable by the application. The container id is fixed as container; guideline and barrier ids must not repeat with components, with priority: component > guideline > barrier.
    • For a child component, the three positions in one direction (e.g., left, middle, right for horizontal) can specify the same-direction positions of the container or other child components (e.g., HorizontalAlign.Start, Center, End for horizontal) as anchors. If more than two anchors are set in the same direction, Start and Center (horizontal) or Top and Center (vertical) take precedence. For example, if left is anchored to the container’s Start, middle to Center, and right to End, and the component width and container width cannot satisfy all three constraints, Start and Center constraints are prioritized.
    • When both the child component size set in the front-end and relative layout rules exist, the drawing size of the child component depends on the constraints (this rule changed in API Version 11, where the drawing size depends on the front-end set size).
    • Additional offset can be set after alignment (bias was added in API Version 11, and offset is no longer recommended).
    • From API Version 11, in the RelativeContainer component, setting width/height to auto means adapting to child components.
    • When width is set to auto, if child components in the horizontal direction use the container as an anchor, auto does not take effect (same for the vertical direction).
    • The margin of child components in the relative layout container differs from the general attribute margin, meaning the distance to the anchor in that direction. If there is no anchor in that direction, the margin does not take effect.
    • When the guideline position is not declared or is an invalid value (e.g., undefined), it takes the start: 0 position; only one of start or end needs to be declared, with start taking precedence if both are declared.
    • When the container’s size in a direction is declared as “auto”, the guideline position in that direction can only be declared using start (percentage is not allowed).
    • Vertical guidelines and barriers can only be used as horizontal anchors for components (vertical anchor takes 0), while horizontal guidelines and barriers can only be used as vertical anchors (horizontal anchor takes 0).
    • Chains are formed by dependency relationships between components. For example, a minimum horizontal chain of components A and B requires anchor1 <– A <—> B –> anchor2, i.e., A has a left anchor, B has a right anchor, A’s right anchor is B’s Start, and B’s left anchor is A’s End.
    • The chain direction and style are declared in the chainMode interface of the chain head component; the bias attribute of elements within the chain is invalid, and the chain head’s bias applies to the entire chain.
    • If the size of elements within the chain exceeds the chain anchor constraints, the excess is evenly distributed on both sides. In a Packed chain, the excess distribution can be set via bias.
  • Special cases:
    • If the child component size cannot be determined by constraints and its own size attribute, it will not be drawn.
    • Mutually dependent or circularly dependent child components will not be drawn.
    • If two or more positions in the same direction set anchors but the anchor positions are in reverse order, the child component size is 0 (not drawn).

Reference demo example:

@Component
export struct CommentItem {
  index: number = 0

  build() {
    Column() {
      RelativeContainer() {
        Image($r("app.media.xxx")).width(30).height(30).id("ivHead1" + this.index)

        Image($r("app.media.xxx")).width(30).height(30).id("ivHead2" + this.index).alignRules({
          top: { anchor: "ivHead1" + this.index, align: VerticalAlign.Top },
          left: { anchor: "ivHead1" + this.index, align: HorizontalAlign.End }
        })

        Image($r("app.media.xxx")).width(30).height(30).id("ivHead3" + this.index).alignRules({
          top: { anchor: "ivHead1" + this.index, align: VerticalAlign.Bottom },
          left: { anchor: "ivHead1" + this.index, align: HorizontalAlign.Start }
        })
        Image($r("app.media.xxx")).width(30).height(30).id("ivHead4" + this.index).alignRules({
          top: { anchor: "ivHead2" + this.index, align: VerticalAlign.Bottom },
          left: { anchor: "ivHead3" + this.index, align: HorizontalAlign.End }
        })

      }.width("auto").height("auto").padding(13)
    }.width('100%')

  }
}


@Entry
@Component
struct Index3 {

  build() {
    Column() {
      List() {
        ForEach([1, 2, 3], (item: number, index: number) => {
          ListItem() {
            CommentItem({ index: index })
          }
        })
      }
    }.height("100%")
  }
}

2. How to optimize high-performance lists in HarmonyOS?

Stock lists trigger multiple data updates per second, causing continuous refreshes of list item data. Fast scrolling in this scenario leads to frame drops. What technology should be used for optimization?

For large list data and complex list components, use LazyForEach for data lazy loading. Refer to: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-rendering-control-lazyforeach-V5

LazyForEach iterates data on demand from the provided data source and creates corresponding components during each iteration. When used in a scrolling container, the framework creates components on demand based on the container’s visible area and destroys/recycles components when they scroll out of view to reduce memory usage.

Usage limitations:

  • LazyForEach must be used within a container component. Only List, Grid, Swiper, and WaterFlow support data lazy loading (configurable cachedCount for buffering visible and adjacent data); other components load all data at once.
  • LazyForEach relies on generated keys to determine whether to refresh child components. If keys do not change, the corresponding child components will not be refreshed.
  • When using LazyForEach in a container component, only one LazyForEach is allowed. For example, List should not contain both ListItem and ForEach/LazyForEach, nor multiple LazyForEach instances.
  • Each LazyForEach iteration must create exactly one child component (the child component generation function has one root component).
  • The generated child component must be allowed in the LazyForEach parent container.
  • LazyForEach can be included in if/else conditional rendering, and if/else can appear within LazyForEach.
  • The key generator must produce a unique value for each data item. Duplicate keys will cause rendering issues for UI components.
  • LazyForEach must use a DataChangeListener object for updates; reassigning the first parameter dataSource will cause exceptions, and changes to state variables in dataSource will not trigger UI refresh.
  • For high-performance rendering, when updating UI via the DataChangeListener’s onDataChange method, generate keys different from the original to trigger component refresh.
  • LazyForEach must be used with the @Reusable decorator to enable node reuse (decorate the LazyForEach list component with @Reusable).

Key generation rules:

During LazyForEach rendering, the system generates a unique and persistent key for each item to identify the component. When the key changes, the ArkUI framework treats the array element as replaced/modified and creates a new component based on the new key.

LazyForEach provides a keyGenerator parameter (a function) for custom key generation. If not defined, the default key generator is used: (item: Object, index: number) => { return viewId + ‘-‘ + index.toString(); }, where viewId is generated during compilation and consistent within the same LazyForEach component.

3. How to center text in HarmonyOS?

How to set text to center display? Setting height and lineHeight to the same value does not center the text.

Reference demo:

@Entry
@Component
struct Pagetext {
  @State message: string = 'Hell';
  build() {
    Row() {
      Column() {
        Text(this.message)
          .width(70)
          .height(30)
            // .lineHeight(30)
          .textAlign(TextAlign.Center)
          .backgroundColor('#99000000')
            // .align(Alignment.TopEnd)
          .border({
            radius: 15
          })
          .fontSize(17)
          .fontColor(Color.White)
      }
      .width('100%')
    }
    .height('100%')
  }
}

4. How to get the current size of a control in HarmonyOS?

Use the component area event onAreaChange(event: (oldValue: Area, newValue: Area) => void) to obtain the component size.

Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-universal-component-area-change-event-V5

5. In the willClick listener callback of HarmonyOS, is there a way to get page/route information of the clicked control?

Through willClick to listen for control clicks, can pageinfo/route information be obtained via frameNode?

There are no related interfaces on frameNode, so pageinfo/route information cannot be obtained via frameNode.


This content originally appeared on DEV Community and was authored by kouwei qing