HarmonyOS:弹出框蒙层控制

一、简介

开发者对弹出框的定制不仅限于弹出框里的内容,对弹出框蒙层的定制需求也逐渐增加。本文介绍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,取消默认点击蒙层时弹窗消失。

bash 复制代码
// 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,将默认的模态弹出框变为非模态弹出框。

bash 复制代码
// 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,实现蒙层区域和蒙层颜色的设置。

bash 复制代码
// 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对蒙层在导航栏和状态栏的延伸效果。

bash 复制代码
// 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,实现弹出框与蒙层整体的动画。

bash 复制代码
// 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,实现弹出框中蒙层单独的动画定制能力。

bash 复制代码
// 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接口在动画的打开和关闭时可进行定制,示例代码如下:

bash 复制代码
// 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();
        })
    }
  }
}

六、完整示例

效果图

示例代码

bash 复制代码
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%')
  }
}
相关推荐
大咖分享课2 小时前
HarmonyOS 6 有哪些新变化、新功能?
华为·harmonyos
EterNity_TiMe_2 小时前
autoconf 工具 OpenHarmony PC 适配指南
华为·harmonyos
爱笑的眼睛113 小时前
深入HarmonyOS USB设备管理:从基础到高级开发
华为·harmonyos
ifeng09183 小时前
HarmonyOS远程真机调试实战:云测与设备管控技巧
华为·harmonyos
爱笑的眼睛113 小时前
HarmonyOS应用开发深度解析:@State状态管理的进阶技巧
华为·harmonyos
流影ng3 小时前
【HarmonyOS】状态管理V2
华为·harmonyos
Kisang.14 小时前
【HarmonyOS】性能优化——组件的封装与复用
华为·性能优化·typescript·harmonyos·鸿蒙
ifeng091816 小时前
HarmonyOS网络请求优化实战:智能缓存、批量处理与竞态处理
网络·缓存·harmonyos
HMSCore21 小时前
【FAQ】HarmonyOS SDK 闭源开放能力 — Notification Kit
harmonyos