DEV Community

Cover image for [Learn HarmonyOS Next Knowledge Daily] ASON Tool, Custom Tabbar, musl, Text Abnormal Truncation, etc.
kouwei qing
kouwei qing

Posted on

[Learn HarmonyOS Next Knowledge Daily] ASON Tool, Custom Tabbar, musl, Text Abnormal Truncation, etc.

[Learn HarmonyOS Next Knowledge Daily] ASON Tool, Custom Tabbar, musl, Text Abnormal Truncation, etc.

1. How to use the ASON tool to implement conversion between Sendable types and JSON data?

ASON supports developers in parsing JSON strings and generating shared data for cross-concurrency domain transmission. Meanwhile, ASON also supports converting shared data into JSON strings.

import { ArkTSUtils, collections, lang } from '@kit.ArkTS';

// Parse JSON to Sendable data
type ISendable = lang.ISendable;
let jsonText = '{"name": "John", "age": 30, "city": "ChongQing"}';
let obj = ArkTSUtils.ASON.parse(jsonText) as ISendable;

// Serialize Sendable data to JSON
let arr = new collections.Array(1, 2, 3);
let str = ArkTSUtils.ASON.stringify(arr);
Enter fullscreen mode Exit fullscreen mode

Reference address: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-arkts-utils-V5#arktsutilsason

2. How to add other components to the tabBar in Tabs?

Currently, many Tabs components have a filter/more icon in the rightmost tabBar. However, the system Tabs component cannot add other components to the tabBar. Customization can be used to implement adding other components to the tabBar in Tabs.

import componentUtils from '@ohos.arkui.componentUtils';

@Entry
@Component
struct TabsExample22 {
  @State tabArray: Array<number> = [0, 1, 2]
  private controller: TabsController = new TabsController()
  @State currentIndex: number = 0
  @State animationDuration: number = 300
  @State indicatorLeftMargin: number = 0
  @State indicatorWidth: number = 0
  private tabsWidth: number = 0

  // Individual tab
  @Builder
  Tab(tabName: string, tabItem: number, tabIndex: number) {
    Row({ space: 20 }) {
      Text(tabName).fontSize(18)
        .fontColor(tabItem === this.currentIndex ? Color.Red : Color.Black)
        .id(tabIndex.toString())
        .onAreaChange((oldValue: Area, newValue: Area) => {
          if (this.currentIndex === tabIndex && (this.indicatorLeftMargin === 0 || this.indicatorWidth === 0)) {
            if (newValue.position.x != undefined) {
              let positionX = Number.parseFloat(newValue.position.x.toString())
              this.indicatorLeftMargin = Number.isNaN(positionX) ? 0 : positionX
            }
            let width = Number.parseFloat(newValue.width.toString())
            this.indicatorWidth = Number.isNaN(width) ? 0 : width
          }
        })
    }
    .justifyContent(FlexAlign.Center)
    .constraintSize({ minWidth: 35 })
    .width(80)
    .height(35)
    .borderRadius({ topLeft: 10, topRight: 10 })
    .onClick(() => {
      this.controller.changeIndex(tabIndex)
      this.currentIndex = tabIndex
    })

  }

  build() {
    Column() {
      // Tab bar
      Stack({ alignContent: Alignment.TopStart }) {
        Scroll() {
          Row() {
            ForEach(this.tabArray, (item: number, index: number) => {
              this.Tab("页签 " + item, item, index)
            })


            Text('+')
              .width(36)
              .height(50)
              .fontSize(28)
              .borderRadius(5)
              .margin({ left: 88 })
              .padding({ left: 5, bottom: 2 })
          }
          .justifyContent(FlexAlign.Start)
        }
        .align(Alignment.Start)
        .scrollable(ScrollDirection.Horizontal)
        .scrollBar(BarState.Off)
        .width('100%')

        Column()
          .width(this.indicatorWidth)
          .height(2)
          .backgroundColor(Color.Red)
          .borderRadius(2)
          .margin({ left: this.indicatorLeftMargin, top: 38 })
      }
      .width('100%')

      .width('100%')

      // Tabs
      Tabs({ barPosition: BarPosition.Start, controller: this.controller }) {
        ForEach(this.tabArray, (item: number, index: number) => {
          TabContent() {
            Text('我是页面 ' + item + " 的内容")
              .height(300)
              .width('100%')
              .fontSize(30)
          }
          .backgroundColor(Color.Pink)
        })
      }
      .onAreaChange((oldValue: Area, newValue: Area) => {
        let width = Number.parseFloat(newValue.width.toString())
        this.tabsWidth = Number.isNaN(width) ? 0 : width
      })
      .barWidth('100%')
      .barHeight(0)
      .width('100%')
      .height('100%')
      .backgroundColor('#F1F3F5')
      .animationDuration(this.animationDuration)
      .onChange((index: number) => {
        this.currentIndex = index // Listen to changes in index to switch tab content.
      })
      .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
        // Triggered when the switching animation starts. The underline slides with the page while the width fades.
        this.currentIndex = targetIndex
        let targetIndexInfo = this.getTextInfo(targetIndex)
        this.startAnimateTo(this.animationDuration, targetIndexInfo.left, targetIndexInfo.width)
      })
      .onAnimationEnd((index: number, event: TabsAnimationEvent) => {
        // Triggered when the switching animation ends. The underline animation stops.
        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event)
        this.startAnimateTo(0, currentIndicatorInfo.left, currentIndicatorInfo.width)
      })
      .onGestureSwipe((index: number, event: TabsAnimationEvent) => {
        // Triggered frame-by-frame during page swiping.
        let currentIndicatorInfo = this.getCurrentIndicatorInfo(index, event)
        this.currentIndex = currentIndicatorInfo.index
        this.indicatorLeftMargin = currentIndicatorInfo.left
        this.indicatorWidth = currentIndicatorInfo.width
      })
    }
    .height('100%')
  }

  // Get component size, position, translation, scaling, rotation, and affine matrix attribute information.
  private getTextInfo(index: number): Record<string, number> {
    let modePosition: componentUtils.ComponentInfo = componentUtils.getRectangleById(index.toString());
    return { 'left': px2vp(modePosition.windowOffset.x), 'width': px2vp(modePosition.size.width) }
  }

  private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
    let nextIndex = index
    if (index > 0 && event.currentOffset > 0) {
      nextIndex--
    } else if (index < 3 && event.currentOffset < 0) {
      nextIndex++
    }
    let indexInfo = this.getTextInfo(index)
    let nextIndexInfo = this.getTextInfo(nextIndex)
    let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth)
    let currentIndex = swipeRatio > 0.5 ? nextIndex : index // When the page swipes more than half, the tabBar switches to the next page.
    let currentLeft = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * swipeRatio
    let currentWidth = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * swipeRatio
    return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth }
  }

  private startAnimateTo(duration: number, leftMargin: number, width: number) {
    animateTo({
      duration: duration, // Animation duration
      curve: Curve.Linear, // Animation curve
      iterations: 1, // Number of plays
      playMode: PlayMode.Normal, // Animation mode
      onFinish: () => {
        console.info('play end')
      }
    }, () => {
      this.indicatorLeftMargin = leftMargin
      this.indicatorWidth = width
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

3. What is the support status of the C/musl library?

HarmonyOS uses musl as the C standard library. The musl library is a lightweight, fast, simple, and free open-source libc library. For detailed introduction, refer to the musl official reference manual. For differences between musl and glibc, refer to musl vs glibc functional comparison.

musl version numbers:

  • Starting from HarmonyOS 4.0, the version was upgraded to 1.2.3.
  • Starting from HarmonyOS 5.0, the version was upgraded to 1.2.5.

Supported capabilities:

Provides header files and library function interfaces compatible with C99, C11, and POSIX standards, but not fully compatible.

4. How to solve the abnormal ellipsis truncation when the Text component's text content is a mix of Chinese, numbers, and English?

When using the Text component with content mixing Chinese, numbers, and English, setting TextOverFlow to show an ellipsis for overflowing text may cause abnormal truncation.

When the Text component sets the wordBreak(WordBreak.BREAK_ALL) property, for Non-CJK text, line breaks can be made between any two characters to achieve normal truncation.

@Entry
@Component
struct Index {
  @State text: string = '2年·VIP会员 3个月期·8GB·230mm·花漾粉'

  build() {
    Column() {
      Text(this.text)
        .width(200)// Set maximum width
        .maxLines(1)// Single line display
        .textOverflow({ overflow: TextOverflow.Ellipsis })// Show ellipsis for overflow
        .ellipsisMode(EllipsisMode.END)// After setting word break rule to WordBreak.BREAK_ALL
        .wordBreak(WordBreak.BREAK_ALL)
        .textAlign(TextAlign.JUSTIFY)
        .backgroundColor(Color.Green)
        .fontSize(16)
        .fontColor(Color.Red)
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

5. What is the standard for HarmonyOS encoding and decoding interfaces?

encodeURIComponent is a built-in capability of TS. URI encoding is based on the RFC 3986 standard.

Top comments (0)