【最新鸿蒙应用开发】——合理使用自定义弹框

自定义弹窗选型

合理选择不同的系统能力实现弹窗,有利于提升应用开发效率,实现更好的功能需求,因此了解自定义弹窗的选型和差异非常重要。在应用开发中,为了选择出合适的弹窗选型,从使用场景上,需要重点关注以下两点:

  • 弹窗与界面代码解耦

    在开发业务逻辑时,例如遇到一些网络请求失败的场景,需要触发相应的弹窗提醒用户进行操作,由于在任何页面都有可能触发对应的弹窗,此时弹窗不是与某个页面相关联,这个情况下,就需要弹窗与界面的解耦。

  • 弹窗在界面跳转后保留

    在一些权限配置页,用户首次进入应用时会弹出权限配置弹窗,让用户进行操作,此时若点击跳转到隐私详情页面,返回后弹窗需要保留在页面上。

从能力角度,系统提供了四种不同的方式来实现自定义弹窗,分别是CustomDialog、promptAction、UIContext.getPromptAction、Navigation.Dialog,在开发业务时,需要结合每种弹窗的特点来选择弹窗。

  • CustomDialog弹窗,必须在@Component struct内部定义,即在UI层创建控制器,当一个页面需要弹出多个自定义弹窗时,就需要创建对应个数的CustomDialogController,这会造成UI层代码冗余,无法做到弹窗与界面的解耦。

  • promptAction弹窗,为了解决CustomDialog弹窗的问题,支持了UI元素复用机制@Builder,但依赖UI组件。

  • UIContext.getPromptAction弹窗,基于promptAction弹窗演进而来,支持全局自定义弹窗,不依赖UI组件,依赖UIContext,支持在非页面文件中使用,弹窗内容支持动态修改,支持自定义弹窗圆角半径、大小和位置,适合在与页面解耦的全局弹窗自定义弹窗显示和退出动画等场景下使用。

  • Navigation.Dialog弹窗,基于Navigation路由形式,以Component组件页面存在于路由栈中,以进出栈的方式打开或关闭弹窗,可以实现弹窗与UI界面解耦,默认透明显示,适合在切换页面弹窗不消失场景下使用。

上述四种弹窗的使用区别,可以从是否支持弹窗与界面代码解耦、弹窗在界面跳转后是否保留这两个方面去进行对比,总结如下:

CustomDialogpromptActionUIContext.getPromptActionNavigation.Dialog
弹窗与界面代码解耦不支持不支持支持支持
弹窗在界面跳转后保留

在对解耦要求不高的情况下,可以使用上面CustomDialog、promptAction两个弹窗,本文围绕开发时主要常见的场景和问题,介绍UIContext.getPromptAction、Navigation.Dialog两个弹窗的使用。

用鸿蒙showCustomMsg提示框(标题和内容无法设置样式居中,总结就是一个字:丑!)

static showCustomMsg(title: string, content: string | Resource, confirmBtn?: string, cancelBtn?: string,
  confirm?: () => void, cancel?: () => void): void {
  promptAction.showDialog({
    title: title ?? "提示",
    message: content,
    buttons: [
      {
        text: cancelBtn ?? "取消",
        color: "#000000"
      },
      {
        text: confirmBtn ?? "确认",
        color: "#4169E1"
      }
    ]
  }).then(data => {
    if (data.index == 1) {
      if (confirm) {
        confirm()
      }
    } else {
      if (cancel) {
        cancel()
      }
    }
  })
}

直接使用鸿蒙showCustomMsg弹框在一些场景是可以的,但是局限性比较大,在一些别的场景需要自定义样式,或者就只是简单想让标题和内容居中都是没有提供样式来调整,因此我们可以使用以下弹框来自定义。

一、在原生页面使用自定义弹窗

import Logger from '../common/utils/Logger'
​
@CustomDialog
export struct HMCustomDialog {
  controller: CustomDialogController
  title: string | Resource = ''
  message: string | Resource = ''
  leftText: string | Resource = ''
  rightText: string | Resource = ''
  showLeft: boolean = true
  showRight: boolean = true
  cancel: () => void = () => {
  }
  confirm: () => void = () => {
  }
​
  build() {
    Column() {
      Text(this.title)
        .fontSize(18)
        .fontColor(Color.Black)
        .fontWeight(800)
        .margin({ top: 10 })
​
      Text(this.message)
        .fontSize(16)
        .fontColor($r('app.color.font_333333'))
        .margin({ top: 10, bottom: 10 })
​
      Flex({ justifyContent: FlexAlign.SpaceAround }) {
        Button(this.leftText)
          .onClick(() => {
            this.cancel()
            this.controller.close()
          }).backgroundColor(0xffffff)
          .fontColor(Color.Gray)
          .visibility(this.showLeft ? Visibility.Visible : Visibility.None)
​
        Button(this.rightText)
          .onClick(() => {
            this.confirm()
            Logger.debug('confirm')
            this.controller.close()
          }).backgroundColor(0xffffff)
          .fontColor($r('app.color.font_0086f3'))
          .visibility(this.showRight ? Visibility.Visible : Visibility.None)
      }.margin({ bottom: 4 })
    }
  }
}

在父页面使用

MyDialogController: CustomDialogController = new CustomDialogController({
  builder: HMCustomDialog({
    title: '提示',
    message: '您还没有登录',
    leftText: '取消',
    rightText: '去登录',
    showLeft: true,
    showRight: true,
    cancel: () => {
    },
    confirm: () => {
      //去登录
      WindowUtils.getRouter().pushUrl({ url: 'pages/login/LoginPage' })
    },
  }),
  alignment: DialogAlignment.Center
})
​
 build() {
    Column(){
    Button()
    .onClick(()=>{
      this.MyDialogController.open()
​
    })
    }
 }
​

二、在非原生页面(如方法中)需要弹出自定义弹窗时

import { ComponentContent } from '@kit.ArkUI'
import { BusinessError } from '@kit.BasicServicesKit';
import { WindowUtils } from '../common/constants/WindowUtils';
import Logger from '../common/utils/Logger';
​
let contentNode: ComponentContent<Content> | undefined
​
export interface Contents {
  title: string
  message: string
  confirm?: () => void,
  leftText?: string
  rightText?: string
}
​
export async function H5ShowCustomDialog(content: Contents) {
​
  let uiContext = WindowUtils.mainWindow.getUIContext();
  let promptAction = uiContext.getPromptAction();
  contentNode = new ComponentContent(uiContext, wrapBuilder(customDialogComponent), content);
​
  try {
    promptAction.openCustomDialog(contentNode)
​
  } catch (error) {
    let message = (error as BusinessError).message;
    let code = (error as BusinessError).code;
    Logger.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);
  }
}
​
export function H5CloseCustomDialog() {
  let uiContext = WindowUtils.mainWindow.getUIContext();
  let promptAction = uiContext.getPromptAction();
​
  try {
    promptAction.closeCustomDialog(contentNode)
  } catch (error) {
    let message = (error as BusinessError).message;
    let code = (error as BusinessError).code;
    Logger.error(`CloseCustomDialog args error code is ${code}, message is ${message}`);
  } finally {
    contentNode = undefined
  }
}
​
@Builder
function
customDialogComponent(content: Contents) {
  Column() {
    Dialog({
      content: content,
    })
  }
  .width('65%')
  .height(150)
  .borderRadius(15)
  .justifyContent(FlexAlign.Center)
  .backgroundColor(Color.White)
}
​
@Component
export struct Dialog {
  content: Contents = {} as Contents
​
  build() {
    Column() {
      Text(this.content.title)
        .fontSize(18)
        .fontColor(Color.Black)
        .fontWeight(700)
        .margin({ top: 10 })
​
      Text(this.content.message)
        .fontSize(16)
        .fontColor($r('app.color.font_333333'))
        .margin({ top: 10, bottom: 10 })
​
      //适用于非原生页面的两种提示框,传confirm提供确认和取消键,否则只提供确认键
      if (this.content.confirm) {
        Flex({ justifyContent: FlexAlign.SpaceAround }) {
          Button(this.content.leftText ? this.content.leftText : '取消')
            .onClick(() => {
              H5CloseCustomDialog()
​
            }).backgroundColor(0xffffff)
            .fontColor(Color.Gray)
​
          Button(this.content.rightText ? this.content.rightText : '确定')
            .onClick(() => {
              if (this.content.confirm) {
                this.content.confirm()
              }
            }).backgroundColor(0xffffff)
            .fontColor($r('app.color.font_0086f3'))
        }.margin({ bottom: 4 })
      } else {
        Button('确定')
          .onClick(() => {
            H5CloseCustomDialog()
​
          }).backgroundColor(0xffffff)
          .fontColor($r('app.color.font_0086f3'))
      }
    }.justifyContent(FlexAlign.SpaceBetween).width('100%').height('100%')
  }
}

调用封装好的方法即可

第一种样式

let content: Contents = {
  title: '提示',
  message: e,
}
H5ShowCustomDialog(content)

第二种样式

const confirm: () => void = () => {
  Toolkit.cleanAppCache()
  H5CloseCustomDialog()
}
let cache = (bundleStats.cacheSize / 1024 / 1024)
let content: Contents = {
  title: '温馨提示',
  message: `缓存大小:${cache > 1 ? cache.toFixed(2) + 'MB' : (cache * 1024).toFixed() + 'KB'}`,
  rightText:'确认清理',
  confirm: confirm
}
H5ShowCustomDialog(content)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值