DEV Community

Cover image for Using Semi-modal in Lists, Custom Toast, Popup Following, Image Base64 Encoding, Routing Optimization
kouwei qing
kouwei qing

Posted on

Using Semi-modal in Lists, Custom Toast, Popup Following, Image Base64 Encoding, Routing Optimization

【Daily HarmonyOS Next Knowledge】Using Semi-modal in Lists, Custom Toast, Popup Following, Image Base64 Encoding, Routing Optimization

1. How to use semi-modal bindSheet in List or Grid in HarmonyOS?

There is a sharing popup-like page that needs to pop up a semi-modal page when clicking each item.

Refer to the following code:

@Entry
@Component
struct BindSheetDemo {
  // Semi-modal transition display/hide control
  @State isShowSheet: boolean = false;
  @State isShowDetailSheet: boolean = false;
  private menuList: string[] = ['Live Room', 'Related Content', 'More'];
  private detailList: string[] = ['Live Room 111111', 'Related Content 22222222', 'More 334455665'];

  // Build the semi-modal display interface via @Builder
  @Builder
  mySheet() {
    Column() {
      Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
        ForEach(this.menuList, (item: string) => {
          Text(item)
            .fontSize(16)
            .fontColor(0x333333)
            .backgroundColor(0xf1f1f1)
            .borderRadius(8)
            .margin(10)
            .padding(10)
            .onClick(() => {
              this.isShowDetailSheet = !this.isShowDetailSheet;
            })
        })
      }
      .bindSheet(this.isShowDetailSheet, this.myDetailSheet(), {
        // height: 550,
        dragBar: true,
        onDisappear: () => {
          this.isShowDetailSheet = !this.isShowDetailSheet;
        }
      })
      .padding({ top: 18 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.White)
  }

  @Builder
  myDetailSheet() {
    Column() {
      Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
        ForEach(this.detailList, (item: string) => {
          Text(item)
            .fontSize(16)
            .fontColor(0x333333)
            .backgroundColor(0xf1f1f1)
            .borderRadius(8)
            .margin(10)
            .padding(10)
        })
      }
      .padding({ top: 18 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.White)
  }

  build() {
    Column() {
      Text('Live Room')
        .fontSize(28)
        .padding({ top: 30, bottom: 30 })
      Column() {
        Row() {
          Row()
            .width(10)
            .height(10)
            .backgroundColor('#a8a8a8')
            .margin({ right: 12 })
            .borderRadius(20)

          Column() {
            Text('Click to View')
              .fontSize(16)
              .fontWeight(FontWeight.Medium)
          }
          .alignItems(HorizontalAlign.Start)

          Blank()

          Row()
            .width(12)
            .height(12)
            .margin({ right: 15 })
            .border({
              width: { top: 2, right: 2 },
              color: 0xcccccc
            })
            .rotate({ angle: 45 })
        }
        .borderRadius(15)
        .shadow({ radius: 100, color: '#ededed' })
        .width('90%')
        .alignItems(VerticalAlign.Center)
        .padding({ left: 15, top: 15, bottom: 15 })
        .backgroundColor(Color.White)
        .bindSheet(this.isShowSheet, this.mySheet(), {
          height: 150,
          dragBar: false,
          onDisappear: () => {
            this.isShowSheet = !this.isShowSheet;
          }
        })
        .onClick(() => {
          this.isShowSheet = !this.isShowSheet;
        })
      }
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor(0xf1f1f1)
  }
}
Enter fullscreen mode Exit fullscreen mode

2. How to customize the toast style in HarmonyOS?

CustomDialog supports customization for popups. Is there a way to customize the UI style for toasts? If the system currently lacks toast customization capabilities, what official recommendations are there to implement toast-like functionality?

Toasts do not support customization, but CustomDialog can be used for full customization. PromptAction.openCustomdialog is recommended, which supports decoupling from the page and only requires passing UIContext to implement popups.

Reference: https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/js-apis-arkui-UIContext.md#opencustomdialog12

openCustomDialog<T extends Object>(dialogContent: ComponentContent<T>, options?: promptAction.BaseDialogOptions): Promise<void>

Creates and pops up a custom dialog corresponding to dialogContent with a Promise async callback. The dialog style fully follows the settings in dialogContent, similar to setting customStyle: true for CustomDialog. Currently, isModal = true and showInSubWindow = true cannot be used simultaneously.

3. When pushing to the next page from a HarmonyOS popup, the popup follows to the next page. How to bind the popup to the current page?

When pushing to the next page from a popup, the popup follows, but we want the popup to bind to the current page.

Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-common-components-custom-dialog-V5

Reference demo:

import router from '@ohos.router';
@CustomDialog
export default struct UserPrivacyDialog {
  controller: CustomDialogController = new CustomDialogController({ builder: '' });
  cancel: Function = () => {
  };
  confirm: Function = () => {
  };
  visible: Visibility = Visibility.None

  build() {
    Column() {
      Text('This is a Popup')
      Button('Jump')
        .onClick(() => {
          router.pushUrl({
            url: 'pages/Second'
          })
        }).backgroundColor(0xffffff).fontColor(Color.Red)
    }
    .margin({ top: 22 })
    .justifyContent(FlexAlign.SpaceEvenly)
  }
}

@Entry
@Component
struct Index {
  @State textValue: string = 'Hello World'
  @State visible: Visibility = Visibility.None

  build() {
    Stack() {
      Row() {
        Column() {
          Button('Click')
            .onClick(() => {
              if (this.visible == Visibility.Visible) {
                this.visible = Visibility.None
              } else {
                this.visible = Visibility.Visible
              }
            })
            .backgroundColor(0x777474)
            .fontColor(0x000000)
        }
        .width('100%')
      }
      .height('100%')
      .backgroundColor(0x885555)
      Text('')
        .onClick(() => {
          if (this.visible == Visibility.Visible) {
            this.visible = Visibility.None
          } else {
            this.visible = Visibility.Visible
          }
        })
        .width('100%')
        .height('100%')// Transparency can be adjusted
        .opacity(0.16)
        .backgroundColor(0x000000)
        .visibility(this.visible)
      Column() {
        GridRow({
          columns: { xs: 1, sm: 4, md: 8, lg: 12 },
          breakpoints: {
            value: ["400vp", "600vp", "800vp"],
            reference: BreakpointsReference.WindowSize
          },
        }) {
          GridCol({
            span: { xs: 1, sm: 2, md: 4, lg: 8 },
            offset: { xs: 0, sm: 1, md: 2, lg: 2 }
          }) {
            Column() {
              Flex({ justifyContent: FlexAlign.SpaceAround }) {
                UserPrivacyDialog();
              }.margin({ bottom: 10 })
            }
            .backgroundColor(0xffffff)
            .visibility(this.visible)
            .clip(true)
            .borderRadius(20)
          }
        }
      }.width('95%') // Set popup width
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

4. How to encode images as Base64 in HarmonyOS?

How to encode images obtained via CameraKit pick as Base64.

Reference demo:

let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 };
let imagePackerApi = image.createImagePacker();
const context: Context = getContext(this);
const resourceMgr = context.resourceManager;
let imageBuffer = await resourceMgr.getMediaContent($r('app.media.ic_low'));
const imageSource: image.ImageSource = image.createImageSource(imageBuffer.buffer);
let decodingOptions: image.DecodingOptions = {
  editable: true,
  desiredPixelFormat: 3,
  rotate: 90
}

// Create PixelMap and perform simple rotation and scaling
imageSource.createPixelMap(decodingOptions).then((pixelMap: PixelMap) => {
  this.pixelMap = pixelMap;
  // Convert PixelMap to Base64 (requires a packing process first)
  imagePackerApi.packing(pixelMap, packOpts).then((data: ArrayBuffer) => {
    let base64Str = buffer.from(data).toString('base64');
    let resultBase64Str = "data:image/png;base64," + base64Str;
    this.resultBase64Str = resultBase64Str;
  }).catch((error: BusinessError) => {
    console.error('Failed to pack the image. Error: ' + error);
  });
  pixelMap.release();
});

// Key tip: Directly converting PixelMap to Base64 is incorrect (example of wrong approach):
let pixelMap = await imageSource.createPixelMap(opts);
console.log("pixelMap.getPixelBytesNumber():" + pixelMap.getPixelBytesNumber());
let arrayBuffer = new ArrayBuffer(pixelMap.getPixelBytesNumber());
pixelMap.readPixelsToBuffer(arrayBuffer);
console.log("arrayBuffer" + arrayBuffer);
let base64Str = buffer.from(arrayBuffer).toString(Constants.BASE_64);
let resultBase64Str = "data:image/png;base64," + base64Str;
Enter fullscreen mode Exit fullscreen mode

Obtaining sandbox paths:

import UIAbility from '@ohos.app.ability.UIAbility';
export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage) {
    let context = this.context;
    let pathDir = context.filesDir;
  }
}
Enter fullscreen mode Exit fullscreen mode

Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/app-sandbox-directory-V5

The app sandbox is a security isolation mechanism to prevent malicious path traversal. The visible directory range for an app is the "app sandbox directory", which includes:

  • A dedicated directory mapped in internal storage for each app, consisting of the "app file directory" and essential system files.
  • Restricted visibility to protect app data from other apps.
  • App files can be saved and processed in the "app file directory"; system files are read-only; user files require specific APIs and user authorization.

5. How to optimize routing usage in HarmonyOS?

Can RouterModule be optimized to automatically determine the current NavStack, or will using a unified NavStack cause performance issues?

Currently, router does not support returning to a specified index page. It is recommended to replace router with Navigation, whose popToIndex method meets this scenario.

Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-basic-components-navigation-V5

Top comments (0)