HarmonyOS鸿蒙Next中openCustomDialog mask蒙层如何添加blur效果

HarmonyOS鸿蒙Next中openCustomDialog mask蒙层如何添加blur效果 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-uicontext-custom-dialog

文档里没找到blur相关的api

目前只能外面包一层容器实现blur效果

但是这样有个问题我想实现点击遮罩自动关闭

autoCancel: true,

这个配置项就无效了

因为弹窗占了 100% 100%

然后又尝试给外层容器添加关闭事件

.onClick(() => {
  this.vm.closeDialog()
})

这样就会导致冒泡问题点击 dialog 本身也会触发关闭

这里不知道如何处理了

请问后续有打算内置蒙层模糊的配置项吗

cke_1290.png

cke_28099.png


更多关于HarmonyOS鸿蒙Next中openCustomDialog mask蒙层如何添加blur效果的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复

开发者您好,为了支持该问题走需求评估流程,需要您补充反馈使用场景和需求不满足可能带来的影响,例如:
原始场景:什么样的业务场景?什么样的交互流程?哪一个过程遇到了问题?
影响:什么时间用到?是否高频?有无三方库可以做到?若提供该能力,是否会造成大工作量返工?

更多关于HarmonyOS鸿蒙Next中openCustomDialog mask蒙层如何添加blur效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


你的问题加一个空的点击事件就好

cke_838.png

我自己写了一下你的功能,你可以看看

import { BusinessError } from '@kit.BasicServicesKit';
import { ComponentContent, display, promptAction, UIContext } from '@kit.ArkUI';

export class PromptActionClass {
  static ctx: UIContext;
  static contentNode: ComponentContent<Object>;
  static options: promptAction.BaseDialogOptions;


  static setContext(context: UIContext) {
    PromptActionClass.ctx = context;
  }


  static setContentNode(node: ComponentContent<Object>) {
    PromptActionClass.contentNode = node;
  }


  static setOptions(options: promptAction.BaseDialogOptions) {
    PromptActionClass.options = options;
  }


  static openDialog() {
    if (PromptActionClass.contentNode !== null) {
      PromptActionClass.ctx.getPromptAction().openCustomDialog(PromptActionClass.contentNode, PromptActionClass.options)
        .then(() => {
          console.info('OpenCustomDialog complete.');
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }


  static closeDialog() {
    if (PromptActionClass.contentNode !== null) {
      PromptActionClass.ctx.getPromptAction().closeCustomDialog(PromptActionClass.contentNode)
        .then(() => {
          console.info('CloseCustomDialog complete.');
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }


  static updateDialog(options: promptAction.BaseDialogOptions) {
    if (PromptActionClass.contentNode !== null) {
      PromptActionClass.ctx.getPromptAction().updateCustomDialog(PromptActionClass.contentNode, options)
        .then(() => {
          console.info('UpdateCustomDialog complete.');
        })
        .catch((error: BusinessError) => {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }
}


class Params {
  text: string = "";


  constructor(text: string) {
    this.text = text;
  }
}






@Builder
function buildText(params: Params) {
  //朦层
  Column() {
    //实际弹窗内容
    Column(){
      Text(params.text)
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 36 })
    }
    .backgroundColor('#fff')
    //todo 加入空的点击事件就不会关闭了
    .onClick(()=>{

    })
  }
  .width('100%')
  .height('100%')

  //获取顶部安全区
  // let topHeight = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height;
  // let bottomHeight = win.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR).bottomRect.height;
  // this.topPadding = px2vp(topHeight)
  // this.bottomPadding = px2vp(bottomHeight)
  //.margin({ top: -topHeight })
  .margin({ top: -40 })//todo 此处40需要替换为顶部安全区高度topHeight,因为朦层会侵入安全区,所以做假朦层也要侵入安全区
  .padding({ top: 40 })
  //此处设置沉浸式失效,所以得用 .margin({ top: -topHeight }) 来做沉浸式
  //.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
  .backgroundColor('#ff433535')

  .backdropBlur(20)
  .onClick(() => {
    PromptActionClass.closeDialog();
  })
}


@Entry
@Component
struct Index {
  @State message: string = "hello";
  private ctx: UIContext = this.getUIContext();
  private contentNode: ComponentContent<Object> =
    new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message));


  aboutToAppear(): void {
    PromptActionClass.setContext(this.ctx);
    PromptActionClass.setContentNode(this.contentNode);
    PromptActionClass.setOptions({
      alignment: DialogAlignment.Top,
      offset: { dx: 0, dy: 50 } ,
      maskColor: Color.Red
    });
  }


  build() {
    Row() {
      Column() {
        Button("open dialog and update options")
          .margin({ top: 50 })
          .onClick(() => {
            PromptActionClass.openDialog();
          })

      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
  }
}
@Entry
@Component
struct Index {
  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomBlurDialog(),
  })

  build() {
    Column() {
      Button('click me')
        .onClick(() => {
          this.dialogController.open();
        })
    }.width('100%').margin({ top: 5 })
  }
}

@CustomDialog
struct CustomBlurDialog {
  controller: CustomDialogController
  @State isContentTouched: boolean = false

  build() {
    Stack() {
      // 模糊蒙层
      Column()
        .width('100%')
        .height('100%')
        .backgroundColor(Color.White)
        .backdropBlur(10)
        .onClick(() => this.controller?.close())

      // 弹窗内容
      Column() {
        Text('自定义弹窗')
          .fontSize(20)
          .margin(20)

        Button('关闭')
          .onClick(() => this.controller.close())
      }
      .backgroundColor(Color.White)
      .borderRadius(16)
      .width('80%')
      .hitTestBehavior(HitTestMode.Block)
    }
  }
}

模糊效果选择:优先使用backdropBlur而非外部容器包裹,确保性能最优

事件控制层级:通过hitTestBehavior精准控制事件响应范围

布局结构优化:通过Stack分层实现蒙层与内容的视觉分离

autoCancel替代方案:自行实现点击判断逻辑更灵活可控

autoCancel失效问题

  • 通过.onClick手动绑定蒙层点击事件
  • 点击冒泡问题
  • 给内容容器添加阻断属性

在HarmonyOS Next中,为openCustomDialog的mask蒙层添加blur效果,需使用ModalTransitionStyle配置。在自定义弹窗组件内,通过设置modalTransitionStyle属性为ModalTransitionStyle.BLUR实现蒙层模糊效果。

具体代码示例:

openCustomDialog(this, {
  modalTransitionStyle: ModalTransitionStyle.BLUR,
  builder: CustomDialogComponent
})

该属性直接作用于弹窗蒙层,无需额外样式配置。模糊效果由系统自动处理,适配不同设备。

目前HarmonyOS Next的openCustomDialog确实没有内置mask蒙层的blur模糊效果API。你遇到的问题是合理的,因为当自定义蒙层覆盖整个屏幕时,autoCancel配置会失效。

针对点击冒泡问题,可以通过事件判断来解决:

.onClick((event: ClickEvent) => {
  // 判断点击的是蒙层而不是dialog内容区域
  if (event.target === yourMaskComponent) {
    this.vm.closeDialog()
  }
})

或者使用HitTestBehavior控制点击穿透:

.mask({ 
  type: MaskType.Solid, 
  color: 0x33000000 
})
.hitTestBehavior(HitTestMode.Block)

关于内置模糊效果的需求,建议通过官方反馈渠道提交功能建议。目前推荐的做法还是使用自定义蒙层方案,通过精确控制点击事件处理来解决关闭问题。

回到顶部