一、簡介

開發者對彈出框的定製不僅限於彈出框裏的內容,對彈出框蒙層的定製需求也逐漸增加。本文介紹ArkUI彈出框的蒙層控制,包括點擊蒙層時是否消失、蒙層區域、蒙層顏色和蒙層動畫等特性。

二、使用約束

ArkUI提供多種彈出框,不同類型的彈出框具備不同的蒙層定製能力。詳情請參閲下表:

接口&組件

autoCancel

maskRect

isModal

immersiveMode

openCustomDialog

支持

支持

支持

支持

openCustomDialogWithController

支持

支持

支持

支持

presentCustomDialog

支持

支持

支持

支持

updateCustomDialog

支持

不支持

不支持

不支持

CustomDialog

支持

支持

支持

支持

showDialog

不支持

支持

支持

支持

showAlertDialog

支持

支持

支持

支持

showActionSheet

支持

支持 支持

支持


showActionMenu

不支持

不支持

支持

支持

showDatePickerDialog

不支持

支持

不支持

不支持

CalendarPickerDialog

不支持

不支持

不支持

不支持

showTimePickerDialog

不支持

支持

不支持

不支持

showTextPickerDialog

不支持

支持

不支持

不支持

説明 設置autoCancel參數,可控制彈出框蒙層被點擊時是否消失。
設置maskRect參數,可定製彈出框的蒙層的大小和位置進行定製。此外,蒙層範圍內的事件無法透傳,而蒙層範圍外的事件可以透傳。
設置isModal參數,可定製彈出框的模態狀態:非模態彈出框無蒙層,支持與周圍組件交互;模態彈出框有蒙層,禁止與周圍組件交互。
當levelMode屬性設置為LevelMode.EMBEDDED時,設置immersiveMode參數,可定製彈出框蒙層是否延伸至狀態欄及導航欄。

接口&組件

maskColor

transition

maskTransition

openCustomDialog

支持

支持

支持

openCustomDialogWithController

支持

支持

支持

presentCustomDialog 支持

支持

支持


updateCustomDialog

支持

不支持

不支持

CustomDialog

支持

不支持(可由openAnimation和closeAnimation替代)

不支持

showDialog

不支持

不支持

不支持

showAlertDialog

不支持

支持

不支持

showActionSheet

不支持

支持

不支持

showActionMenu

不支持

不支持

不支持

showDatePickerDialog

不支持

不支持

不支持

CalendarPickerDialog

不支持

不支持

不支持

showTimePickerDialog

不支持

不支持

不支持

showTextPickerDialog

不支持

不支持

不支持

説明 設置maskColor參數,可定製彈出框蒙層的顏色。
設置openAnimation參數,可定製彈出框的進入動畫,同時影響蒙層動畫。該接口僅支持簡單的動畫設置,不支持複雜動畫定製。
設置closeAnimation參數,可定製彈出框的退出動畫,同時影響蒙層動畫。該接口僅支持簡單的動畫設置,不支持複雜動畫定製。
設置transition參數,可定製彈出框的進入和退出動畫,同時影響蒙層動畫。
設置maskTransition參數,可定製彈出框的蒙層動畫。

三、彈出框蒙層顯隱控制

通過autoCancel,isModal展示彈出框在蒙層顯隱控制方面的能力。
設置autoCancel為false,取消默認點擊蒙層時彈窗消失。

// xxx.ets
  autoCancelOpt: promptAction.CustomDialogOptions = {
    builder: () => {
      this.myBuilder();
    },
    autoCancel: false,
  } as promptAction.CustomDialogOptions;

  Button("openCustomDialog autoCancel:false")
    .width('100%')
    .margin({ top: 10 })
    .onClick(() => {
      this.getUIContext().getPromptAction().openCustomDialog(this.autoCancelOpt)
    })

設置isModal為false,將默認的模態彈出框變為非模態彈出框。

// xxx.ets
modalOpt: promptAction.CustomDialogOptions = {
  builder: () => {
    this.myBuilder();
  },
  isModal: false,
} as promptAction.CustomDialogOptions;

Button("openCustomDialog isModal:false")
  .width('100%')
  .margin({ top: 10 })
  .onClick(() => {
    this.getUIContext().getPromptAction().openCustomDialog(this.modalOpt)
  })

四、彈出框蒙層樣式控制

該示例通過maskRect、immersiveMode和maskColor展示彈出框在蒙層樣式控制方面的能力。
設置maskRect和maskColor,實現蒙層區域和蒙層顏色的設置。

// xxx.ets
  maskOpt: promptAction.CustomDialogOptions = {
    builder: () => {
      this.myBuilder();
    },
    maskRect: {
      x: 0,
      y: 10,
      width: '100%',
      height: '90%'
    },
    maskColor: "#33AA0000"
  } as promptAction.CustomDialogOptions;

  Button("openCustomDialog maskOpt")
    .width('100%')
    .margin({ top: 10 })
    .onClick(() => {
      this.getUIContext().getPromptAction().openCustomDialog(this.maskOpt)
    })

在levelMode為LevelMode.EMBEDDED下,展示不同immersiveMode對蒙層在導航欄和狀態欄的延伸效果。

// xxx.ets
  @State immersiveMode: ImmersiveMode = ImmersiveMode.DEFAULT;

  Button("openCustomDialog immersiveMode")
    .width('100%')
    .margin({ top: 10 })
    .onClick(() => {
      this.immersiveMode =
        this.immersiveMode == ImmersiveMode.DEFAULT ? ImmersiveMode.EXTEND : ImmersiveMode.DEFAULT;
      this.getUIContext().getPromptAction().openCustomDialog({
        builder: () => {
          this.myBuilder();
        },
        levelMode: LevelMode.EMBEDDED,
        immersiveMode: this.immersiveMode,
      })
    })

五、彈出框蒙層動畫控制

該示例通過transition和maskTransition分別展示彈出框在蒙層動畫方面的能力。
設置transition,實現彈出框與蒙層整體的動畫。

// xxx.ets
  transitionOpt: promptAction.CustomDialogOptions = {
    builder: () => {
      this.myBuilder();
    },
    transition: TransitionEffect.OPACITY.animation({ duration: 3000 })
  } as promptAction.CustomDialogOptions;

  Button("openCustomDialog transition")
    .width('100%')
    .margin({ top: 10 })
    .onClick(() => {
      this.getUIContext().getPromptAction().openCustomDialog(this.transitionOpt);
    })

設置maskTransition,實現彈出框中蒙層單獨的動畫定製能力。

// xxx.ets
  Button("openCustomDialog maskTransition")
    .width('100%')
    .margin({ top: 10 })
    .onClick(() => {
      this.getUIContext().getPromptAction().openCustomDialog({
        builder: () => {
          this.myBuilder();
        },
        maskTransition: TransitionEffect.OPACITY.animation({ duration: 2000 })
          .combine(TransitionEffect.rotate({ z: 1, angle: 180 })),
      });
    })

CustomDialog雖然不支持transition接口,但與之對應的openAnimation和closeAnimation接口在動畫的打開和關閉時可進行定製,示例代碼如下:

// xxx.ets

@CustomDialog
@Component
struct CustomDialogExample {
  controller?: CustomDialogController;

  build() {
    Column() {
      Text("title")
        .margin(10)
        .fontSize(20)
      Button("button1")
        .margin(10)
        .fontSize(20)
        .onClick(() => {
          this.controller?.close();
        })
      Button("button2")
        .margin(10)
        .fontSize(20)
        .onClick(() => {
          this.controller?.close();
        })
    }.width('100%')
    .height('50%')
  }
}

@Entry
@Component
struct Index {
  animationController: CustomDialogController | null
    = new CustomDialogController({
    builder: CustomDialogExample(),
    closeAnimation: { duration: 2000 },
    openAnimation: { duration: 2000 }
  });

  aboutToDisappear(): void {
    this.animationController = null;
  }

  build() {
    Column() {
      Button("CustomDialogController animate")
        .width('100%')
        .margin({ top: 10 })
        .onClick(() => {
          this.animationController?.open();
        })
    }
  }
}

六、完整示例

效果圖

HarmonyOS:彈出框蒙層控制_HarmonyOS

示例代碼

import { ImmersiveMode, LevelMode, promptAction } from '@kit.ArkUI';

@Entry
@Component
struct TestOpenCustomDialog7 {
  @State immersiveMode: ImmersiveMode = ImmersiveMode.DEFAULT;
  autoCancelOpt: promptAction.CustomDialogOptions = {
    builder: () => {
      this.myBuilder();
    },
    autoCancel: false,
  } as promptAction.CustomDialogOptions;
  modalOpt: promptAction.CustomDialogOptions = {
    builder: () => {
      this.myBuilder();
    },
    isModal: false,
  } as promptAction.CustomDialogOptions;
  maskOpt: promptAction.CustomDialogOptions = {
    builder: () => {
      this.myBuilder();
    },
    maskRect: {
      x: 0,
      y: 10,
      width: '100%',
      height: '90%'
    },
    maskColor: "#33AA0000"
  } as promptAction.CustomDialogOptions;
  transitionOpt: promptAction.CustomDialogOptions = {
    builder: () => {
      this.myBuilder();
    },
    transition: TransitionEffect.OPACITY.animation({ duration: 3000 })
  } as promptAction.CustomDialogOptions;

  @Builder
  myBuilder() {
    Column() {
      Text("title").margin(10).fontSize(20)
      Button("button1").margin(10).fontSize(20)
      Button("button2").margin(10).fontSize(20)
    }.width('100%').height('50%')
  }

  build() {
    Column({space: 10}) {
      Button("openCustomDialog autoCancel:false")
        .width('100%')
        .margin({ top: 10 })
        .onClick(() => {
          this.getUIContext().getPromptAction().openCustomDialog(this.autoCancelOpt)
        })
      Button("openCustomDialog isModal:false")
        .width('100%')
        .margin({ top: 10 })
        .onClick(() => {
          this.getUIContext().getPromptAction().openCustomDialog(this.modalOpt)
        })
      Button("openCustomDialog maskOpt")
        .width('100%')
        .margin({ top: 10 })
        .onClick(() => {
          this.getUIContext().getPromptAction().openCustomDialog(this.maskOpt)
        })
      Button("openCustomDialog transition")
        .width('100%')
        .margin({ top: 10 })
        .onClick(() => {
          this.getUIContext().getPromptAction().openCustomDialog(this.transitionOpt);
        })
      Button("openCustomDialog immersiveMode")
        .width('100%')
        .margin({ top: 10 })
        .onClick(() => {
          this.immersiveMode =
            this.immersiveMode == ImmersiveMode.DEFAULT ? ImmersiveMode.EXTEND : ImmersiveMode.DEFAULT;
          this.getUIContext().getPromptAction().openCustomDialog({
            builder: () => {
              this.myBuilder();
            },
            levelMode: LevelMode.EMBEDDED,
            immersiveMode: this.immersiveMode,
          })
        })
      Button("openCustomDialog maskTransition")
        .width('100%')
        .margin({ top: 10 })
        .onClick(() => {
          this.getUIContext().getPromptAction().openCustomDialog({
            builder: () => {
              this.myBuilder();
            },
            maskTransition: TransitionEffect.OPACITY.animation({ duration: 2000 })
              .combine(TransitionEffect.rotate({ z: 1, angle: 180 })),
          });
        })
    }
    .width('100%')
    .height('100%')
  }
}