DEV Community

Cover image for [Daily HarmonyOS Next Knowledge] List Collapse Animation, Obfuscation Issue, bindPopup Problems, etc.
kouwei qing
kouwei qing

Posted on

[Daily HarmonyOS Next Knowledge] List Collapse Animation, Obfuscation Issue, bindPopup Problems, etc.

[Daily HarmonyOS Next Knowledge] List Collapse Animation, Obfuscation Issue, bindPopup Problems, etc.

1. How to implement list collapse animation effects?

  • When the height of listItem is known, collapse animation can be achieved by controlling height changes.
  • When the height of listItem is unknown, collapse animation can be achieved by adding/removing data in animateTo.

2. How to add compilation parameters in HarmonyOS?

  1. Add in CMakeLists.txt:
# Set build type to Release, which disables debug information
set(CMAKE_BUILD_TYPE Release)

# The -s flag optimizes compilation to generate shorter code
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s")

# Solve symbol conflicts
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-Bsymbolic")

# Unified additions:
# Enable stack protection; capture buffer overflow security issues; code optimization; integer overflow checks, etc.
set(CMAKE_CXX_FLAGS "-fstack-protector-all -D_FORTIFY_SOURCE=2 -O2 -ftrapv -s")
Enter fullscreen mode Exit fullscreen mode
  1. Add in externalnativeoptions configuration: The externalNativeOptions parameter in the module-level build-profile.json5 is the entry for compiling C/C++ files in NDK projects. You can specify the CMake script path via path, configure CMake parameters via arguments, set C++ compiler parameters via cppFlags, and configure compilation architectures via abiFilters:
"externalNativeOptions": {
  "path": "./src/main/cpp/CMakeLists.txt",
  "arguments": "-DCMAKE_BUILD_TYPE=Release",
  "cppFlags": "-fstack-protector-all -D_FORTIFY_SOURCE=2 -O2 -ftrapv -s",
}
Enter fullscreen mode Exit fullscreen mode

3. bindPopup style issues?

Problems:

  1. Inability to change the rounded corner size of the Popup window.
  2. When enableArrow is true, the arrow color is white. Can the arrow color be changed?

Solutions:

4. How to locate obfuscation issues?

Scenario: Debugging works, but Release mode reports errors or crashes.

定位Means:

  1. Add obfuscation configuration -disable-obfuscation to turn off all obfuscation.
  2. Compile in Release mode. If the exception disappears, confirm it is caused by obfuscation.
  3. Comment out the -compact obfuscation configuration to check the specific error location.

Compilation Output Directory: build/default/cache/default/default@HarCompileArkTS/esmodule/release

Cause: Issues arise because attribute names, method names, or parameter names are obfuscated. Use -keep-property-name, -keep-global-name, or -keep to prevent obfuscation of specific elements.

5. Based on what positioning is the offset attribute of BindPopup offset?

What is the reference point for the offset of bindpopup? For example, if offset is set to x: 100, y: 100, based on which point are x and y offset when touching the screen?

Answer: The reference point is the top-left anchor of the bound component.

  • Note: The specifications of bindpopup have changed in 5.0. The写法 in current Webview documents is no longer fully compatible with the long-press menu function. To use bindpopup, add a component with size 0 before the Webview component (at the same layer) to carry bindpopup.
  • According to current UX specifications, a horizontal offset of 7vp is required to ensure the popup menu stays within the screen range.

Sample Code:

import web_webview from '@ohos.web.webview'
import pasteboard from '@ohos.pasteboard'

const TAG = 'ContextMenu';

@Entry
@Component
struct WebComponent {
  controller: web_webview.WebviewController = new web_webview.WebviewController()
  private result: WebContextMenuResult | undefined = undefined;
  @State linkUrl: string = '';
  @State offsetX: number = 0;
  @State offsetY: number = 0;
  @State showMenu: boolean = false;

  @Builder
  // Build custom menu and trigger function interface
  MenuBuilder() {
    // Menu displayed as a vertical list.
    Menu() {
      // Display specific item menu items in Menu.
      MenuItem({
        content: '复制图片',
      })
        .width(100)
        .height(50)
        .onClick(() => {
          this.result?.copyImage();
          this.showMenu = false;
        })
      MenuItem({
        content: '剪切',
      })
        .width(100)
        .height(50)
        .onClick(() => {
          this.result?.cut();
          this.showMenu = false;
        })
      MenuItem({
        content: '复制',
      })
        .width(100)
        .height(50)
        .onClick(() => {
          this.result?.copy();
          this.showMenu = false;
        })
      MenuItem({
        content: '粘贴',
      })
        .width(100)
        .height(50)
        .onClick(() => {
          this.result?.paste();
          this.showMenu = false;
        })
      MenuItem({
        content: '复制链接',
      })
        .width(100)
        .height(50)
        .onClick(() => {
          let pasteData = pasteboard.createData('text/plain', this.linkUrl);
          pasteboard.getSystemPasteboard().setData(pasteData, (error) => {
            if (error) {
              return;
            }
          })
          this.showMenu = false;
        })
      MenuItem({
        content: '全选',
      })
        .width(100)
        .height(50)
        .onClick(() => {
          this.result?.selectAll();
          this.showMenu = false;
        })
    }
    .width(150)
    .height(300)
    .backgroundColor("#eeeeee")
  }

  build() {
    Column() {
      Row()
        .width(0)
        .height(0)
        .position({ x: 0, y: 0 })
        .bindPopup(this.showMenu,
          {
            builder: this.MenuBuilder(),
            enableArrow: false,
            placement: Placement.LeftTop,
            targetSpace: 0,
            shadow: {
              radius: 0
            },
            offset: { x: this.offsetX - 7, y: this.offsetY },
            mask: false,
            onStateChange: (e) => {
              if (!e.isVisible) {
                this.showMenu = false;
                this.result!.closeContextMenu();
              }
            }
          })

      Web({ src: '', controller: this.controller })// Trigger custom popup
        .onControllerAttached(() => {
          this.controller.setCustomUserAgent(this.controller.getUserAgent() + " Android")
          this.controller.loadUrl($rawfile("OnContextMenuShow/index.html"))
        })// Trigger custom popup
        .onContextMenuShow((event) => {
          if (event) {
            this.result = event.result
            console.info("x coord = " + event.param.x())
            console.info("link url = " + event.param.getLinkUrl())
            this.linkUrl = event.param.getLinkUrl()
          }
          console.info(TAG, `x: ${this.offsetX}, y: ${this.offsetY}`);
          this.showMenu = true;
          this.offsetX = Math.max(px2vp(event?.param.x() ?? 0) - 0, 0);
          this.offsetY = Math.max(px2vp(event?.param.y() ?? 0) - 0, 0);
          return true
        })
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)