DEV Community

Cover image for [Daily HarmonyOS Next Knowledge] View Touch Hotspot Range, Direct Clipboard Assignment, Component Screenshot
kouwei qing
kouwei qing

Posted on

[Daily HarmonyOS Next Knowledge] View Touch Hotspot Range, Direct Clipboard Assignment, Component Screenshot

[Daily HarmonyOS Next Knowledge] View Touch Hotspot Range, Direct Clipboard Assignment, Component Screenshot, Portrait/Landscape Switch, Screenshot Prevention, etc.

1. How to view the touch hotspot range?

Currently, the responseRegion can only be obtained through customization.

Reference document: Touch Hotspot Settings

@Entry
@Component
struct TouchTargetExample {
  @State text: string = ''
  @State x: number = 0
  @State y: number = 0
  @State reg_width: string = '50%'
  @State reg_height: string = '100%'

  build() {
    Column({ space: 20 }) {
      Text("{x:0,y:0,width:'50%',height:'100%'}")

      // The hotspot width is half of the button; clicking the right side has no response.
      Button('button')
        .responseRegion({ x: this.x, y: this.y, width: this.reg_width, height: this.reg_height })
        .onClick(() => {
          this.text = 'button clicked'
          console.log('button clicked: ' + this.x + ' ' + this.y + ' ' + this.reg_width + ' ' + this.reg_height)
        })

      Text(this.text).margin({ top: 10 })
    }.width('100%').margin({ top: 100 })
  }
}
Enter fullscreen mode Exit fullscreen mode

2. How to directly copy content to the clipboard?

Directly add text to the clipboard without popping up a text selection dialog.

Reference code:

import { pasteboard } from '@kit.BasicServicesKit';
import { promptAction } from '@kit.ArkUI';

@Entry
@Component
export struct CopyText {
  private textContent: string = '复制我'  // "Copy Me"

  build() {
    Column() {
      Text(this.textContent)
        .fontSize($r('sys.float.ohos_id_text_size_body3'))
        .borderRadius(9)
        .borderWidth(1)
        .padding({ left: 8, right: 8 })
        .fontColor($r('sys.color.ohos_id_color_text_primary'))
        .fontWeight(FontWeight.Medium)
        .opacity($r('sys.float.ohos_id_alpha_content_secondary'))
        .onClick(() => copyText(this.textContent))
    }
  }
}

function copyText(text: string) {
  const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text)
  const systemPasteboard = pasteboard.getSystemPasteboard()
  systemPasteboard.setData(pasteboardData)  // Put data into the clipboard
  systemPasteboard.getData().then((data) => {
    if (data) {
      promptAction.showToast({ message: '复制成功' })  // "Copy successful"
    } else {
      promptAction.showToast({ message: '复制失败' })  // "Copy failed"
    }
  })
}
Enter fullscreen mode Exit fullscreen mode

3. How to save component screenshots? Store PixelMap in the system album or app sandbox.

Step 1: Confirm the capability required for component screenshotting: componentSnapshot

Screenshot capabilities include window screenshot (window.snapshot()) and component screenshot (@ohos.arkui.componentSnapshot). Choose the appropriate API based on business needs.

Step 2: Application authorization and configuration

To save to the system album, apply for the album management permission in module.json5:

"requestPermissions": [
  {
    "name": "ohos.permission.WRITE_IMAGEVIDEO",
    "reason": "$string:reason",
    "usedScene": {
      "abilities": [
        "EntryFormAbility"
      ],
      "when": "inuse"
    }
  },
]
Enter fullscreen mode Exit fullscreen mode

Obtain permissions at the page entry:

import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
const permissions: Array<Permissions> = ['ohos.permission.WRITE_IMAGEVIDEO'];

function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
  let atManager: abilityAccessCtrl.AtManager =
    abilityAccessCtrl.createAtManager();
  atManager.requestPermissionsFromUser(context, permissions).then((data) => {
    let grantStatus: Array<number> = data.authResults;
    let length: number = grantStatus.length;
    for (let i = 0; i < length; i++) {
      if (grantStatus[i] === 0) {
        // User authorized, proceed with the target operation
      } else {
        // User denied authorization, prompt for mandatory authorization and guide to settings
        return;
      }
    }
    // Authorization successful
  }).catch((err: BusinessError) => {
    console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
  })
}

aboutToAppear(): void {
  reqPermissionsFromUser(permissions, this.context)
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Call component screenshot to get PixelMap

/* Component screenshot */
clickToComponentSnapshot() {
  // "root" is the component ID
  componentSnapshot.get("root", (error: Error, pixmap: image.PixelMap) => {
    if (error) {
      console.log("error: " + JSON.stringify(error))
      return;
    }
    console.log('截图成功')  // "Screenshot successful"
    this.pixmap = pixmap
  })
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Save to system album or app sandbox

// Save to system album
async savePixmap2SysHelper() {
  if (!this.pixmap) {
    return
  }
  const imgBuffer = await this.transferPixelMap2Buffer(this.pixmap)

  /* Get the photo access helper instance for album operations */
  let helper = photoAccessHelper.getPhotoAccessHelper(getContext(this))

  /* Create image/video assets with specified type and suffix, return result via callback */
  const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png')
  const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
  await fs.write(file.fd, imgBuffer)
  /* Close the file */
  await fs.close(file.fd)
}

/* Convert PixelMap to image buffer */
transferPixelMap2Buffer(pixelMap: image.PixelMap): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => {
    /* Packing options: format (only jpg/webp), quality, buffer size (default 10M) */
    let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 }
    const imagePackerApi = image.createImagePacker()
    imagePackerApi.packing(pixelMap, packOpts).then((buffer: ArrayBuffer) => {
      resolve(buffer)
    }).catch((err: BusinessError) => {
      reject()
    })
  })
}

/* Save to app sandbox */
async savePixmal2SystemFileManager() {
  if (!this.pixmap) {
    return
  }
  const imgBuffer = await this.transferPixelMap2Buffer(this.pixmap)
  const file = fs.openSync(this.filesDir + `/${DateUtil.getTimeStamp()}.png`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  await fs.write(file.fd, imgBuffer)
  /* Close the file */
  await fs.close(file.fd)
}
Enter fullscreen mode Exit fullscreen mode

4. How to implement portrait/landscape switching for a page?

Use setPreferredOrientation to switch between portrait and landscape: setPreferredOrientation

import { window } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  private portrait: boolean = true
  changeOrientation = () => {
    // Get the current page context
    let context = getContext(this)
    window.getLastWindow(context).then((mainWindow) => {
      this.changeOrientationInternal(mainWindow)
    }).catch((error: ESObject) => {
      console.log('getMainWindow error: ' + JSON.stringify(error))
    })
  }

  changeOrientationInternal(lastWindow: window.Window) {
    if (this.portrait) {
      // Switch to landscape
      lastWindow.setPreferredOrientation(window.Orientation.LANDSCAPE).then(() => {
        console.log('setPreferredOrientation success')
        this.portrait = !this.portrait
      }).catch((error: ESObject) => {
        console.log('setPreferredOrientation failure' + JSON.stringify(error))
      })
    } else {
      // Switch to portrait
      lastWindow.setPreferredOrientation(window.Orientation.PORTRAIT).then(() => {
        console.log('setPreferredOrientation success')
        this.portrait = !this.portrait
      }).catch((error: ESObject) => {
        console.log('setPreferredOrientation failure: ' + JSON.stringify(error))
      })
    }
  }

  build() {
    Column() {
      Text(this.message)
        .id('Index19HelloWorld')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
      Button('横竖屏切换')  // "Switch Portrait/Landscape"
        .onClick(() => {
          this.changeOrientation()
        })
    }
    .height('100%')
    .width('100%')
    .backgroundColor(Color.Green)
  }
}
Enter fullscreen mode Exit fullscreen mode

5. How to implement screenshot prevention?

  1. When setting the window to privacy mode, add relevant permissions in the module.json5 file of the entry:

    Permission configuration screenshot

  2. Use setWindowPrivacyMode to enable privacy mode:

import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index20 {
  @State message: string = 'Hello World';
  window?: window.Window;

  aboutToAppear(): void {
    window.getLastWindow(getContext(this)).then((mainWindow) => {
      this.setWindowPrivacyMode(mainWindow, true)
    }).catch((error: ESObject) => {
      console.log("getMainWindow error: " + JSON.stringify(error))
    })
  }

  setWindowPrivacyMode(windowClass: window.Window, isPrivacyMode: boolean) {
    try {
      // Set the window to privacy mode (prevents screenshot/screen recording)
      let promise = windowClass.setWindowPrivacyMode(isPrivacyMode);
      promise.then(() => {
        console.info('Succeeded in setting the window to privacy mode.');
      }).catch((err: BusinessError) => {
        console.error('Failed to set the window to privacy mode. Cause: ' + JSON.stringify(err));
      });

      console.info(`setWindowPrivacyMode 已执行`);  // "setWindowPrivacyMode executed"
    } catch (exception) {
      console.error('Failed to set the window to the privacy mode. Cause:' + JSON.stringify(exception));
    }
  }

  build() {
    Column() {
      Text(this.message)
        .id('Index20HelloWorld')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)