自定義彈窗選型
合理選擇不同的系統能力實現彈窗,有利於提升應用開發效率,實現更好的功能需求,因此瞭解自定義彈窗的選型和差異非常重要。在應用開發中,為了選擇出合適的彈窗選型,從使用場景上,需要重點關注以下兩點:
- 彈窗與介面程式碼解耦
在開發業務邏輯時,例如遇到一些網路請求失敗的場景,需要觸發相應的彈窗提醒使用者進行操作,由於在任何頁面都有可能觸發對應的彈窗,此時彈窗不是與某個頁面相關聯,這個情況下,就需要彈窗與介面的解耦。
- 彈窗在介面跳轉後保留
在一些許可權配置頁,使用者首次進入應用時會彈出許可權配置彈窗,讓使用者進行操作,此時若點選跳轉到隱私詳情頁面,返回後彈窗需要保留在頁面上。
系統提供了四種不同的方式來實現自定義彈窗,分別是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%') } }