DEV Community

Cover image for Tab Area Occlusion, System Cropping Function, JSON Conversion Issues, Click Events, Animation Continuous Execution Problem
kouwei qing
kouwei qing

Posted on

Tab Area Occlusion, System Cropping Function, JSON Conversion Issues, Click Events, Animation Continuous Execution Problem

[Daily HarmonyOS Next Knowledge] Tab Area Occlusion, System Cropping Function, JSON Conversion Issues, Click Events, Animation Continuous Execution Problem

1. HarmonyOS Tabbar area occlusion problem?

When using Tabbar as the bottom navigation with a List inside, occlusion occurs.

Solution: Set the barOverlap attribute to false to eliminate occlusion.

2. How to invoke the system cropping function for images in HarmonyOS?

Image cropping requires operations on PixelMap.

Reference documentation: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/image-arkts-dev-V5

Button('Image Crop').fancy()
  .onClick(() => {
    let region: image.Region = { x: 300, y: 0, size: { height: 500, width: 700 } };
    if (this.imagePixelMap !== undefined) {
      this.imagePixelMap.crop(region).then(async () => {
        if (this.imagePixelMap !== undefined) {
          let pixel = await copyPixelMap(this.imagePixelMap);
          this.imagePixelMap.release();
          this.imagePixelMap = pixel;
          console.info('Sucessed in setting crop.');
        }
      }).catch((err: BusinessError) => {
        console.error('Failed to crop pixelmap.');
      })
    }
  })

async function copyPixelMap(imagePixel: PixelMap): Promise<image.PixelMap> {
  let imageInfo: image.ImageInfo = await imagePixel.getImageInfo();
  console.info(`copyPixelMapSize: width:${imageInfo?.size.width} height:${imageInfo?.size.height}`);
  let newRegion: image.Region = {
    size: { height: imageInfo.size.height, width: imageInfo.size.width },
    x: 0,
    y: 0
  }
  let newArea: image.PositionArea = {
    pixels: new ArrayBuffer(imageInfo.size.height * imageInfo.size.width * 4),
    offset: 0,
    stride: imageInfo.stride,
    region: newRegion
  }
  await imagePixel.readPixels(newArea);
  let opts: image.InitializationOptions = { editable: true, pixelFormat: 4, size: imageInfo.size };
  let imagePixelCache = await image.createPixelMap(newArea.pixels, opts);
  return imagePixelCache;
}
Enter fullscreen mode Exit fullscreen mode

Simple example reference: For third-party library image cropping, refer to ImageKnife, which provides a cropping interface request.crop().

Documentation: https://gitee.com/openharmony-tpc/ImageKnife

import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo, picker } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { image } from '@kit.ImageKit';

@Entry
@Component
struct Index {
  @State origin: PixelMap | undefined = undefined
  @State origin2: PixelMap | undefined = undefined
  private uri:string = ''

  private async decodeImage(uri: string) {
    try {
      let file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY)
      const imageSourceApi = image.createImageSource(file.fd)
      imageSourceApi.getImageInfo(0, (error: BusinessError, imageInfo) => {
        if (imageInfo === undefined) {
          // log.e(error)
        }
        console.log(`imageInfo:  ${JSON.stringify(imageInfo)}`)
      })
      return await imageSourceApi.createPixelMap()
    } catch (error) {
      // log.e(error)
      return undefined
    }
  }
  build() {
    Column() {
      Button('Add Photo')
        .onClick(async () => {
          let uris = await selectPhoto({
            MIMEType: picker.PhotoViewMIMETypes.IMAGE_TYPE,
            maxSelectNumber: 1,
            isPhotoTakingSupported: false,
            recommendationOptions: {
              recommendationType: photoAccessHelper.RecommendationType.PROFILE_PICTURE,
            }
          })
          if (uris.length === 0) {
            return
          }
          this.uri = uris[0];
          this.origin = await this.decodeImage(uris[0])

        })
      Image(this.origin)
        .width('100%')
        .height('100%')
        .layoutWeight(1)
        .objectFit(ImageFit.Contain)


      Button('Crop Photo')
        .onClick(async () => {
          this.origin2 = await this.decodeImage(this.uri)
          if (this.origin2) {
            let info = await this.origin2.getImageInfo()
            this.origin2.crop({
              x: 0, y: 0,
              size: {
                width: info.size.width,
                height: info.size.height / 2
              }
            })
            let pixel = await copyPixelMap(this.origin2);
            this.origin2.release();
            this.origin2 = pixel;
          }
        })

      Image(this.origin2)
        .width('100%')
        .height('100%')
        .layoutWeight(1)
        .objectFit(ImageFit.Contain)
    }
    .width(`100%`)
  }
}


const PHOTO_DEFAULT_SELECT_NUMBER: number = 9; // Quantity

async function copyPixelMap(imagePixel: PixelMap): Promise<image.PixelMap> {
  let imageInfo: image.ImageInfo = await imagePixel.getImageInfo();
  console.info(`copyPixelMapSize: width:${imageInfo?.size.width} height:${imageInfo?.size.height}`);
  let newRegion: image.Region = {
    size: { height: imageInfo.size.height, width: imageInfo.size.width },
    x: 0,
    y: 0
  }
  let newArea: image.PositionArea = {
    pixels: new ArrayBuffer(imageInfo.size.height * imageInfo.size.width * 4),
    offset: 0,
    stride: imageInfo.stride,
    region: newRegion
  }
  await imagePixel.readPixels(newArea);
  let opts: image.InitializationOptions = { editable: true, pixelFormat: 4, size: imageInfo.size };
  let imagePixelCache = await image.createPixelMap(newArea.pixels, opts);
  return imagePixelCache;
}

/**
Launches the photoPicker interface in selection mode, allowing users to select one or more images/videos.
@param options
@returns
*/
async function selectPhoto(options?: PhotoSelectOptions): Promise<Array<string>> {
  try {
    if (!options) {
      options = new PhotoSelectOptions();
    }
    if (!options.MIMEType) { // Allowed media file types; defaults to images and videos if not specified.
      options.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
    }
    if (!options.maxSelectNumber) { // Maximum number of media files to select, default is 9
      options.maxSelectNumber = PHOTO_DEFAULT_SELECT_NUMBER;
    }
    if (options.isPhotoTakingSupported === undefined) {
      options.isPhotoTakingSupported = true; // Enables photo taking.
    }
    if (options.isEditSupported === undefined) {
      options.isEditSupported = true; // Enables photo editing.
    }
    if (options.isSearchSupported === undefined) {
      options.isSearchSupported = true; // Enables search.
    }
    let photoSelectOptions: photoAccessHelper.PhotoSelectOptions = {
      MIMEType: options.MIMEType,
      maxSelectNumber: options.maxSelectNumber,
      isPhotoTakingSupported: options.isPhotoTakingSupported,
      isEditSupported: options.isEditSupported,
      isSearchSupported: options.isSearchSupported,
      recommendationOptions: options.recommendationOptions,
      preselectedUris: options.preselectedUris
    }
    let photoPicker = new photoAccessHelper.PhotoViewPicker();
    let photoSelectResult: photoAccessHelper.PhotoSelectResult = await photoPicker.select(photoSelectOptions)
    if (photoSelectResult && photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) {
      return photoSelectResult.photoUris
    } else {
      return [];
    }
  } catch (err) {
    console.error(err)
    return [];
  }
}
class PhotoSelectOptions {
  MIMEType?: photoAccessHelper.PhotoViewMIMETypes = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; // Allowed media file types; defaults to images and videos if not specified.
  maxSelectNumber?: number = PHOTO_DEFAULT_SELECT_NUMBER; // Maximum number of media files to select (default is 50, maximum is 500).
  isPhotoTakingSupported?: boolean = true; // Enables photo taking.
  isEditSupported?: boolean = true; // Enables photo editing.
  isSearchSupported?: boolean = true; // Enables search.
  recommendationOptions?: photoAccessHelper.RecommendationOptions; // Enables photo recommendations.
  preselectedUris?: Array<string>; // URIs of preselected images.
}
Enter fullscreen mode Exit fullscreen mode

3. HarmonyOS JSON conversion issues in release mode (parameter names are modified)?

When converting data to a JSON string, it works in test build mode but fails in release mode, as parameter names are altered.

Reason: DevEco Studio enables code obfuscation by default for Stage models (API 10 and above) in release mode.

Solution: Disable code obfuscation for debugging in release mode.

Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5

4. The global click event listener in HarmonyOS has x and y properties in GestureEvent, but they are not exposed as external properties or methods?

let callback = (event: GestureEvent, frameNode: FrameNode) => {
  console.error("PageEvent didClick, event: {}", JSON.stringify(frameNode))
}
Enter fullscreen mode Exit fullscreen mode

Solution: Use ClickEvent to access x and y properties.

Reference documentation: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-arkui-uicontext-V5#ZH-CN_TOPIC_0000001884757690__onwillclick12-1

5. The Lottie animation on the HarmonyOS home page continues running even after page navigation?

The home page's cube card (e.g., live broadcast card) has a Lottie animation that persists after switching pages, causing device overheating.

Solution: Manually control animations during page navigation using:

  • lottie.pause('name') to pause the animation.
  • lottie.play('name') to resume the animation.

Top comments (0)