鸿蒙项目实战(三):自定义弹窗开发实践

自定义弹窗选型

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

  • 弹窗与界面代码解耦

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

  • 弹窗在界面跳转后保留

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

系统提供了四种不同的方式来实现自定义弹窗,分别是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界面解耦,默认透明显示,适合在切换页面弹窗不消失场景下使用。

总结如下:

使用示例如下:

一、CustomerDialog

1、定义:

// 自定义提示弹框
// @CustomerDialog
@CustomDialog
export struct TipDialog {
  @State title: string = "提示" // 标题
  @State message: string = ""; // 提示内容
  @State cancelValue: string = "取消"; //取消按钮文案
  @State confirmValue: string = "确定"; //确定按钮文案
  cancel?: () => void // 取消事件
  confirm?: () => void // 确定事件
  controller: CustomDialogController = new CustomDialogController({
    builder: TipDialog()
  })

  build() {
    Column() {
      Text(this.title)
        .width('100%')
        .height(40)
        .textAlign(TextAlign.Center)
        .fontColor(Color.White)
        .backgroundColor($r('app.color.dialog_title_bg'))
        .borderRadius({ topLeft: 10, topRight: 10 })
      Text(this.message)
        .height(70)
        .width('100%')
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.White)
      Row() {
        Text(this.cancelValue)
          .layoutWeight(1)
          .backgroundColor(Color.White)
          .fontColor(Color.Black)
          .textAlign(TextAlign.Center)
          .height(40)
          .borderRadius({ bottomLeft: 10 })
          .onClick(() => {
            if (this.cancel) {
              this.cancel()
            }
          })
        Text(this.confirmValue)
          .layoutWeight(1)
          .backgroundColor($r('app.color.main_color'))
          .fontColor(Color.White)
          .textAlign(TextAlign.Center)
          .height(40)
          .borderRadius({ bottomRight: 10 })
          .onClick(() => {
            if (this.confirm) {
              this.confirm()
            }
          })
      }
    }.width('100%')
  }
}

 

2、使用

import {TipDialog} from '../../components/dialogs/TipDialog'

@Entry
@Component
struct More {
  // 有多少个弹框,就需要定义多少个CustomDialogController
  // 造成UI层代码冗余,无法做到弹窗与界面的解耦。
  controller:CustomDialogController= new CustomDialogController({
    builder : TipDialog({
      message: '点击了内容',
      confirm: ()=>{
        console.log('点击了确定')
        this.controller.close()
      },
      cancel: ()=>{
        console.log('点击了取消')
        this.controller.close()
      }
    }),
    alignment: DialogAlignment.Center,
    offset: { dx: 0, dy: -20 },
    customStyle: false,
    width:'80%',
    cornerRadius:10,
    backgroundColor: 0xd9ffffff,
  })

  showDialog(){
    this.controller.open()
  }
  build() {
    Row() {
      Column() {
        Button('打开弹框')
          .fontWeight(FontWeight.Bold)
          .onClick(()=>{
            this.showDialog()
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

 

二、UIContext.getPromptAction弹窗

1、定义

// 自定义弹框组件
// 使用UIContext.getPromptAction.openCustomDialog的方式
// https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-custome-dialog-development-practice-V5#section7466312192919
// https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-arkui-uicontext-V5#opencustomdialog12

// 弹框可设置参数
export class DialogParms{
  public title: string = "提示" // 标题
  public message: string = "" // 提示内容
  public cancelValue: string = "取消" // 取消按钮文案
  public confirmValue: string = "确定" // 确定按钮文案
  public cancel?: (() => void) | undefined   // 取消事件
  public confirm?: (() => void) | undefined   // 确定事件
  public setTitle(value: string):void {
    this.title = value
  }
  public setMessage(value: string):void {
    this.message = value
  }
  public setCancelValue(value: string):void {
    this.cancelValue = value
  }
  public setConfirmValue(value: string):void {
    this.confirmValue = value
  }

  public setCancel(value: (() => void) | undefined){
    this.cancel = value
  }

  public setConfirm(value: (() => void) | undefined) {
    this.confirm = value
  }

  constructor(title:string) {
    this.title = title
  }


}

// 全局自定义函数
@Builder
export function  WarmDialog(parms:DialogParms){
  Column() {
    Text(parms.title)
      .width('100%')
      .height(40)
      .textAlign(TextAlign.Center)
      .fontColor(Color.White)
      .backgroundColor($r('app.color.dialog_title_bg'))
      .borderRadius({topLeft:10,topRight:10})
    Text(parms.message)
      .height(70)
      .width('100%')
      .textAlign(TextAlign.Center)
      .backgroundColor(Color.White)
    Row() {
      Text(parms.cancelValue)
        .layoutWeight(1)
        .backgroundColor(Color.White)
        .fontColor(Color.Black)
        .textAlign(TextAlign.Center)
        .height(40)
        .borderRadius({bottomLeft:10})
        .onClick(()=>{
          if (parms.cancel) {
            parms.cancel()
          }
        })
      Text(parms.confirmValue)
        .layoutWeight(1)
        .backgroundColor($r('app.color.main_color'))
        .fontColor(Color.White)
        .textAlign(TextAlign.Center)
        .height(40)
        .borderRadius({bottomRight:10})
        .onClick(()=>{
          if (parms.confirm) {
            parms.confirm()
          }
        })
    }
  }.width('80%')
}

 

2、使用

import { ComponentContent, PromptAction, UIContext } from '@kit.ArkUI';
import {WarmDialog,DialogParms} from '../../components/dialogs/WarmDialog'
@Entry
@Component
struct More {
  uiContext:UIContext = this.getUIContext()

  showDialog(){
    let promptAction:PromptAction = this.uiContext.getPromptAction()
    let dialogParms = new DialogParms("警告")
    dialogParms.setTitle("警告")
    dialogParms.setMessage("这是警告内容")
    dialogParms.setCancel(()=>{
      promptAction.closeCustomDialog(builderView)
      console.log('点击了取消')
    })
    dialogParms.setConfirm(()=>{
      promptAction.closeCustomDialog(builderView)
      console.log('点击了确定')
    })
    let builderView = new ComponentContent(
      this.uiContext,
      wrapBuilder(WarmDialog),dialogParms
    )
    promptAction.openCustomDialog(builderView,{alignment:DialogAlignment.Center},)
  }
  build() {
    Row() {
      Column() {
        Button('打开弹框')
          .fontWeight(FontWeight.Bold)
          .onClick(()=>{
            this.showDialog()
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

 

 

 

posted @ 2024-11-09 08:48  听着music睡  阅读(140)  评论(0编辑  收藏  举报