DEV Community

Cover image for Span Issues, Component Identification Attributes, Property Animation Callbacks, Text-Image Mixing, Relative Layout Problems
kouwei qing
kouwei qing

Posted on

Span Issues, Component Identification Attributes, Property Animation Callbacks, Text-Image Mixing, Relative Layout Problems

[Daily HarmonyOS Next Knowledge] Span Issues, Component Identification Attributes, Property Animation Callbacks, Text-Image Mixing, Relative Layout Problems

1. HarmonyOS Ellipsis Display Issues with Two Spans (Chinese Followed by Overflowing Text)?

When using two spans where the first contains Chinese characters and the second is extremely long, the Ellipsis feature may display incorrectly.

Solution: Set the line break rule using .wordBreak(WordBreak.BREAK_ALL).

Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-text-V5#ZH-CN_TOPIC_0000001893209429__wordbreak11

2. How to Obtain Component Identification Attributes in HarmonyOS?

Use getInspectorByKey + getInspectorByKey(id: string): string to retrieve all attributes of a component with a specified ID (excluding child component information).

Reference code example:

// xxx.ets
import { IntentionCode } from '@ohos.multimodalInput.intentionCode'

class Utils {
  static rect_left: number;
  static rect_top: number;
  static rect_right: number;
  static rect_bottom: number;
  static rect_value: Record<string, number>;

  // Get the rectangular coordinates of a component
  static getComponentRect(key: string): Record<string, number> {
    let strJson = getInspectorByKey(key);
    let obj: Record<string, string> = JSON.parse(strJson);
    console.info("[getInspectorByKey] Current component obj is: " + JSON.stringify(obj));
    let rectInfo: string[] = JSON.parse('[' + obj.$rect + ']');
    console.info("[getInspectorByKey] rectInfo is: " + rectInfo);
    Utils.rect_left = JSON.parse('[' + rectInfo[0] + ']')[0];
    Utils.rect_top = JSON.parse('[' + rectInfo[0] + ']')[1];
    Utils.rect_right = JSON.parse('[' + rectInfo[1] + ']')[0];
    Utils.rect_bottom = JSON.parse('[' + rectInfo[1] + ']')[1];
    return Utils.rect_value = {
      "left": Utils.rect_left, "top": Utils.rect_top, "right": Utils.rect_right, "bottom": Utils.rect_bottom
    };
  }
}

@Entry
@Component
struct IdExample {
  @State text: string = '';

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Button() {
        Text('onKeyTab').fontSize(25).fontWeight(FontWeight.Bold);
      }.margin({ top: 20 }).backgroundColor('#0D9FFB')
      .onKeyEvent(() => {
        this.text = "onKeyTab";
      });

      Button() {
        Text('click to start').fontSize(25).fontWeight(FontWeight.Bold);
      }.margin({ top: 20 })
      .onClick(() => {
        console.info(getInspectorByKey("click"));
        console.info(JSON.stringify(getInspectorTree()));
        this.text = "Button 'click to start' is clicked";
        setTimeout(() => {
          sendEventByKey("longClick", 11, ""); // Send long click event to component with id "longClick"
        }, 2000);
      }).id('click');

      Button() {
        Text('longClick').fontSize(25).fontWeight(FontWeight.Bold);
      }.margin({ top: 20 }).backgroundColor('#0D9FFB')
      .gesture(
        LongPressGesture().onActionEnd(() => {
          console.info('long clicked');
          this.text = "Button 'longClick' is longclicked";
          setTimeout(() => {
            let rect = Utils.getComponentRect('onTouch'); // Get coordinates of component with id "onTouch"
            let touchPoint: TouchObject = {
              id: 1,
              type: TouchType.Down,
              x: rect.left + (rect.right - rect.left) / 2, // Horizontal coordinate relative to component's top-left
              y: rect.top + (rect.bottom - rect.top) / 2, // Vertical coordinate relative to component's top-left
              screenX: rect.left + (rect.right - rect.left) / 2, // Deprecated in API10, use windowX instead
              screenY: rect.left + (rect.right - rect.left) / 2, // Deprecated in API10, use windowY instead
              windowX: rect.left + (rect.right - rect.left) / 2, // Horizontal coordinate relative to app window's top-left
              windowY: rect.left + (rect.right - rect.left) / 2, // Vertical coordinate relative to app window's top-left
              displayX: rect.left + (rect.right - rect.left) / 2, // Horizontal coordinate relative to device screen's top-left
              displayY: rect.left + (rect.right - rect.left) / 2, // Vertical coordinate relative to device screen's top-left
            };
            sendTouchEvent(touchPoint); // Send touch down event
            touchPoint.type = TouchType.Up;
            sendTouchEvent(touchPoint); // Send touch up event
          }, 2000);
        })).id('longClick');

      Button() {
        Text('onTouch').fontSize(25).fontWeight(FontWeight.Bold);
      }.type(ButtonType.Capsule).margin({ top: 20 })
      .onClick(() => {
        console.info('onTouch is clicked');
        this.text = "Button 'onTouch' is clicked";
        setTimeout(() => {
          let rect = Utils.getComponentRect('onMouse'); // Get coordinates of component with id "onMouse"
          let mouseEvent: MouseEvent = {
            button: MouseButton.Left,
            action: MouseAction.Press,
            x: rect.left + (rect.right - rect.left) / 2, // Horizontal coordinate relative to component's top-left
            y: rect.top + (rect.bottom - rect.top) / 2, // Vertical coordinate relative to component's top-left
            screenX: rect.left + (rect.right - rect.left) / 2, // Deprecated in API10, use windowX instead
            screenY: rect.left + (rect.right - rect.left) / 2, // Deprecated in API10, use windowY instead
            windowX: rect.left + (rect.right - rect.left) / 2, // Horizontal coordinate relative to app window's top-left
            windowY: rect.left + (rect.right - rect.left) / 2, // Vertical coordinate relative to app window's top-left
            displayX: rect.left + (rect.right - rect.left) / 2, // Horizontal coordinate relative to device screen's top-left
            displayY: rect.left + (rect.right - rect.left) / 2, // Vertical coordinate relative to device screen's top-left
            stopPropagation: () => {},
            timestamp: 1,
            target: {
              area: {
                width: 1,
                height: 1,
                position: {
                  x: 1,
                  y: 1
                },
                globalPosition: {
                  x: 1,
                  y: 1
                }
              }
            },
            source: SourceType.Mouse,
            pressure: 1,
            tiltX: 1,
            tiltY: 1,
            sourceTool: SourceTool.Unknown
          };
          sendMouseEvent(mouseEvent); // Send mouse event
        }, 2000);
      }).id('onTouch');

      Button() {
        Text('onMouse').fontSize(25).fontWeight(FontWeight.Bold);
      }.margin({ top: 20 }).backgroundColor('#0D9FFB')
      .onMouse(() => {
        console.info('onMouse');
        this.text = "Button 'onMouse' in onMouse";
        setTimeout(() => {
          let keyEvent: KeyEvent = {
            type: KeyType.Down,
            keyCode: 2049,
            keyText: 'tab',
            keySource: 4,
            deviceId: 0,
            metaKey: 0,
            timestamp: 0,
            stopPropagation: () => {},
            intentionCode: IntentionCode.INTENTION_DOWN
          };
          sendKeyEvent(keyEvent); // Send key event
        }, 2000);
      }).id('onMouse');

      Text(this.text).fontSize(25).padding(15);
    }
    .width('100%').height('100%');
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Does HarmonyOS Property Animation Support Callbacks During Execution?

Property animations do not support callbacks during execution. However, Animator animations support the onFrame callback to return the current animation progress.

Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-animator-V5#ZH-CN_TOPIC_0000001893369037__onframe12

4. How to Arrange Images and Text in HarmonyOS?

To achieve a layout where images and text are arranged such that the second line starts with an image from the leftmost position:

Solution: Add .wordBreak(WordBreak.BREAK_ALL) to the Text component.

5. HarmonyOS RelativeContainer Component Limitations Preventing Desired UI Effects?

The RelativeContainer component has limitations for certain UI requirements:

  1. Left element occupying remaining width: Use layoutWeight property.
  2. Element B's height depends on Element A's adaptive height: Use onAreaChange event to dynamically set B's height.
  3. Unable to remove default Indicator margins: Swiper's built-in indicator style has fixed dimensions. Adjust component margins or create a custom indicator.
  4. Getting maximum height of Swiper content: Currently no API to get dimensions of non-visible Swiper components. Set a maximum height instead.

Reference demo:

@Entry
@Component
struct Index {
  private swiperController: SwiperController = new SwiperController();
  @State rightHeight: Length = 80;
  @State swiperData: string[] = ['', ''];
  @State currentIndex: number = 0;

  build() {
    Column() {
      Text('近期需关注')
        .textAlign(TextAlign.Start)
        .fontSize(20)
        .width('100%');
      Text('宝宝能独坐啦').margin({ bottom: 10 })
        .textAlign(TextAlign.Start)
        .width('100%');
      Row() {
        Column() {
          Swiper(this.swiperController) {
            Column() {
              Text('疫苗对比1')
                .fontSize('20');
              Text('#流感疫苗选三价还是四价?')
                .textAlign(TextAlign.Start)
                .width('100%');
            }
            Column() {
              Text('疫苗对比2')
                .fontSize('20');
              Text('#2流感疫苗选三价还是四价?流感疫苗选三价还是四价?流感疫苗选三价还是四价?2');
            }
          }
          .indicator(false)
          .onChange(index => {
            this.currentIndex = index;
          });
          // Custom indicator
          Row({ space: 20 }) {
            ForEach(this.swiperData, (item: string, index: number) => {
              Shape() {
                Rect().width(12).height(5).radius(5).fill(index !== this.currentIndex ? Color.Black : Color.Red)
                  .fillOpacity(0.6);
              }
            });
          }
          .margin({ top: 10 });
        }
        .layoutWeight(1) // Occupy remaining width
        .backgroundColor(Color.Green)
        .onAreaChange((newA: Area, oldA: Area) => {
          this.rightHeight = oldA.height;
        })
        .padding(10);

        Row() {
          Column() {
            Image($r('app.media.app_icon'))
              .width(30)
              .height(30);
            Text("记头围");
          }
          Column() {
            Image($r('app.media.app_icon'))
              .width(30)
              .height(30);
            Text("记体重");
          }
          .margin({ left: 10 });
        }
        .backgroundColor(Color.Green)
        .padding({ top: '20.00vp', right: '10.00vp', bottom: '20.00vp', left: '10.00vp' })
        .margin({ left: 10 })
        .height(this.rightHeight);
      }
      .margin({ bottom: 10 });
    }
    .width('100%')
    .padding(10)
    .backgroundColor(Color.Gray);
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)