DEV Community

kouwei qing
kouwei qing

Posted on

Watermark Addition, List UI Refresh, Scroll Component Overlay, Worker Network Requests, Click Events

[Daily HarmonyOS Next Knowledge] Watermark Addition, List UI Refresh, Scroll Component Overlay, Worker Network Requests, Click Events

1. Is there a method to add watermarks to UI in HarmonyOS?

Refer to the demo:

@Entry
@Component
struct PageWatermark {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  @Builder Watermark() {
    Canvas(this.context)
      .width("100%") .height("100%")
      .hitTestBehavior(HitTestMode.Transparent)
      .onReady(() => {
        this.context.fillStyle = '#10000000'
        this.context.font = "16vp"
        this.context.textAlign = "center"
        this.context.textBaseline = "middle"
        // Draw text watermarks here; image watermarks are also possible
        for (let i = 0; i < this.context.width / 120; i++) {
          this.context.translate(120, 0)
          let j = 0
          for (; j < this.context.height / 120; j++) {
            this.context.rotate(-Math.PI / 180 * 30)
            // The watermark data here is hardcoded; replace it with your own watermark
            this.context.fillText("Watermark Watermark Watermark", -60, -60)
            this.context.rotate(Math.PI / 180 * 30)
            this.context.translate(0, 120) }
          this.context.translate(0, -120 * j)
        }
      })
  }

  build() {
    Column() {
      Text("No data").fontColor("#495057")
      Image($r("app.media.startIcon"))
        .width(300)
        .layoutWeight(1)
        .overlay(this.Watermark())
        .width("100%")
    }
    .height('100%')
    .width('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

2. In HarmonyOS, when clicking a list item, how to modify the property status of the current item and refresh the UI based on property changes?

Refer to the demo:

export class ListModel {
  title: string;
  content: string;
  isComplete: boolean;

  constructor(title: string, content: string, isComplete: boolean) {
    this.title = title;
    this.content = content;
    this.isComplete = isComplete;
  }
}
@Entry
@Component
struct SyncPage {
  @State ListData: Array<ListModel> = [
    new ListModel('Title 1', 'Content 1', true),
    new ListModel('Title 2', 'Content 2', false),
    new ListModel('Title 3', 'Content 3', false),
  ];

  build() {
    Column() {
      List() {
        ForEach(this.ListData, (item: ListModel, index: number) => {
          ListItem() {
            Row() {
              Row() {
                Text(item.title)
                Text(item.content).fontColor('#999999').fontSize(13)
              }

              Image(item.isComplete ? $r('app.media.ic_personal_focus') : $r('app.media.ic_personal_normal'))
                .width(20)
                .height(20)
                .margin(10)
            }
            .justifyContent(FlexAlign.SpaceBetween)
            .width('100%')
            .alignItems(VerticalAlign.Center)
            .height(80)
            .onClick(() => {
              let status = !item.isComplete
              this.ListData.map((el, itemIndex) => {
                if (itemIndex !== index) {
                  el.isComplete = false
                }
              })
              this.ListData.splice(index, 1, new ListModel(item.title, item.content, status))
            })
          }
        })
      }

      Button('Confirm', { type: ButtonType.Normal })
        .onClick(() => {
          console.log('Print selected data in listData')
        })
    }

  }
}
Enter fullscreen mode Exit fullscreen mode

3. When overlaying a component on a Scroll, how to set margins, width, and height?

Refer to the demo:

@Entry
@Component
struct NestedScroll {
  @State listPosition: number = 0; // 0 for scrolling to the top of the List, 1 for the middle, 2 for the bottom.
  private arr: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  private scrollerForScroll: Scroller = new Scroller()
  private scrollerForList: Scroller = new Scroller()

  build() {
    Flex() {
      Scroll(this.scrollerForScroll) {
        Column() {
          List({ space: 20, scroller: this.scrollerForList }) {
            ForEach(this.arr, (item: number) => {
              ListItem() {
                Text("ListItem" + item)
                  .width("100%")
                  .height("100%")
                  .borderRadius(15)
                  .fontSize(16)
                  .textAlign(TextAlign.Center)
                  .backgroundColor(Color.White)
              }.width("100%").height(100)
            }, (item: string) => item)
          }
          .width("100%")
          .height("50%")
          .edgeEffect(EdgeEffect.None)
          .friction(0.6)
          .onReachStart(() => {
            this.listPosition = 0
          })
          .onReachEnd(() => {
            this.listPosition = 2
          })
          .onScrollFrameBegin((offset: number) => {
            if ((this.listPosition == 0 && offset <= 0) || (this.listPosition == 2 && offset >= 0)) {
              this.scrollerForScroll.scrollBy(0, offset)
              return { offsetRemain: 0 }
            }
            this.listPosition = 1
            return { offsetRemain: offset };
          })
          AreaTest()
        }
      }
      .width("100%").height("100%")
    }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding(20)
  }
}


@Component struct AreaTest {
  build() {
    Text("Scroll Area")
      .width("100%")
      .height("40%")
      .backgroundColor(0X330000FF)
      .fontSize(16)
      .textAlign(TextAlign.Center)
      .margin(90)
  }
}
Enter fullscreen mode Exit fullscreen mode

4. In HarmonyOS, how to process all network requests through multi-threading using workers?

For frequent network requests and database storage—operations that are time-consuming and have logical sequences—use workers. Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/worker-introduction-V5

Main role of Worker: Provides a multi-threading runtime environment for applications, allowing scripts to run in background threads separately from the host thread. This avoids blocking the host thread with compute-intensive or high-latency tasks. For specific interface information and usage, see Worker.

Worker operation mechanism diagram

  • The thread creating the Worker is the host thread (not necessarily the main thread; worker threads can also create Worker child threads). The Worker's own thread is the Worker child thread (or Actor thread/worker thread).
  • Each Worker child thread and host thread have independent instances (infrastructure, objects, code segments, etc.), so starting each Worker incurs memory overhead. Limit the number of Worker child threads.
  • Communication between Worker child threads and the host thread is message-based, using serialization for command and data interaction.

Precautions:

  • When creating a Worker, there are manual and automatic methods. Manual creation requires configuring the Worker thread directory and files.
  • The path rules for Worker thread files in the constructor vary by version.
  • Manually manage the Worker lifecycle. A maximum of 64 Worker child threads can run simultaneously.
  • Worker threads can only use thread-safe libraries (e.g., non-thread-safe UI libraries are unsupported).
  • Serialized data is limited to 16MB.
  • Register the onerror interface in the host thread to avoid jscrash on Worker thread exceptions.
  • Cross-HAP Worker thread file usage is unsupported.
  • Configure dependencies for HAR/HSP before referencing them.
  • AppStorage is unsupported in Worker threads.

5. In HarmonyOS, how to better capture single-click events?

Using TapGesture({count: 1}).onAction((event: GestureEvent) => { Code segment A }) may trigger Code segment A even if the finger is lifted after a delay or after sliding. For typical single-clicks requiring quick lifts, use a GestureGroup with exclusive recognition mode, adding empty long-press and pan gestures.

Sample code:

Button('Gesture Verification')
  .gesture(GestureGroup(GestureMode.Exclusive,
    TapGesture({count: 1}).onAction(() => {
      // Code segment A
    }),
    LongPressGesture(),
    PanGesture()
  ))
Enter fullscreen mode Exit fullscreen mode

Top comments (0)