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%')
  }
}
相关推荐
颜颜yan_6 小时前
Git Cola 鸿蒙 PC 版适配全记录:从 Qt 桌面工具到 ArkTS 原生应用
git·qt·harmonyos
承渊政道7 小时前
Python IDLE鸿蒙PC适配全记录:用 ArkUI 重建编辑、运行、Shell 与基础调试闭环
python·microsoft·harmonyos·鸿蒙系统·pc端
User_芊芊君子7 小时前
RapidSVN 鸿蒙 PC 适配全记录:用 ArkUI 重建工作台,打通本地 SVN 操作闭环
华为·svn·harmonyos
lqj_本人8 小时前
WinMerge 鸿蒙 PC 适配全记录:以 Qt 重建桌面外壳,打通文件与文件夹差异闭环
qt·华为·harmonyos
不羁的木木8 小时前
给鸿蒙 App 增加唤起系统邮件发送能力 —— flutter_email_sender 的鸿蒙使用指南
flutter·华为·harmonyos
承渊政道8 小时前
PostgreSQL 鸿蒙 PC 适配全记录:从原生交叉编译到 HNP 数据库服务闭环
数据库·postgresql·harmonyos·鸿蒙系统·pc端
lqj_本人8 小时前
Tftpd64 鸿蒙 PC 适配全记录:用 Qt 重建一组可运行的 UDP 网络服务
qt·udp·harmonyos
User_芊芊君子8 小时前
RStudio 鸿蒙 PC 适配全记录:以 Qt 原生工作区承载嵌入式 R
qt·r语言·harmonyos
ai安歌8 小时前
Git Extensions 鸿蒙 PC 适配全记录:从 WinForms 客户端到 ArkUI 原生工作台
git·华为·harmonyos
●VON8 小时前
Flutter 鸿蒙插件适配实战:用 accurate_storage_info 0.1.1 查询总量、可用量与已用量
flutter·华为·harmonyos