鴻蒙(HarmonyOS)常見的三種彈窗方式

安辉發表於2024-08-31

最近有一個想法,做一個針對鴻蒙官方API的工具箱專案,介紹常用的控制元件,以及在專案中如何使用,今天介紹Harmony中如何實現彈窗功能。

警告彈窗

警告彈窗是一個App中非常常用的彈窗,例如:

  • 刪除一條記錄,提示一下使用者:您確定要刪除嗎?
  • 在App首頁,點選返回時,提示一下使用者:您確定要退出App嗎?

使用AlertDialog.show方法進行彈窗,這個方法支援傳入以下三個類中的任意一個物件

  • AlertDialogParamWithConfirm
  • AlertDialogParamWithButtons
  • AlertDialogParamWithOptions

以AlertDialogParamWithButtons物件進行說明,下面表格介紹常用屬性:

引數名 引數型別 必填 引數描述
title ResourceStr 彈窗標題
message ResourceStr 彈窗內容
autoCancel boolean 點選遮障層時,是否關閉彈窗。預設值:true
primaryButton 按鈕的文字內容、文字色、按鈕背景色和點選回撥
secondaryButton 按鈕的文字內容、文字色、按鈕背景色和點選回撥
cancel () => void 點選遮障層關閉dialog時的回撥
alignment DialogAlignment 彈窗在豎直方向上的對齊方式。預設值:DialogAlignment.Default

接下來,我們用程式碼來實現一下:

AlertDialog.show({
    title:"彈窗標題",
    message:"這是彈窗內容",
    autoCancel:true,//點選遮障層時,是否關閉彈窗。預設值:true
    alignment: DialogAlignment.Center,//彈窗在豎直方向上的對齊方式。預設值:DialogAlignment.Default
    primaryButton: {
        value: "取消",
        fontColor: '#181818',
        action: () => {
            AppUtil.showToast("點選了取消按鈕");
        }
    },
    secondaryButton: {
        value: "確定",
        fontColor: $r('app.color.mainColor'),
        action: () => {
            AppUtil.showToast("點選了確定按鈕");
        }
    },
    cornerRadius:12,//彈窗邊框弧度
    width:'80%', //彈窗寬度
    cancel:()=>{
        AppUtil.showToast("點選遮障層關閉dialog時的回撥");
    }
})

效果圖:

參考官方連結:

https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V2/ts-methods-alert-dialog-box-0000001478341185-V2

自定義彈窗

自定義彈窗相比警告彈窗更為靈活,支援自定義彈窗的樣式與內容。

自定義彈窗的引數:
引數名 引數型別 必填 引數描述
builder CustomDialog 自定義彈窗內容構造器。
cancel () => void 點選遮障層退出時的回撥。
autoCancel boolean 是否允許點選遮障層退出。預設值:true
alignment DialogAlignment 彈窗在豎直方向上的對齊方式。預設值:DialogAlignment.Default
offset Offset 彈窗相對alignment所在位置的偏移量。
customStyle boolean 彈窗容器樣式是否自定義。預設值:false,彈窗容器的寬度根據柵格系統自適應,不跟隨子節點;高度自適應子節點,最大為視窗高度的90%;圓角為24vp。
gridCount8+ number 彈窗寬度佔柵格寬度的個數。預設為按照視窗大小自適應,異常值按預設值處理,最大柵格數為系統最大柵格數。

程式碼實現

我們使用自定義彈窗實現隱私政策彈窗,新建PrivacyPolicyDialogBackUp類,也就是內容構造器,使用@CustomDialog修飾,內部有一個屬性controller: CustomDialogController,這些都是常規寫法,然後在build中實現介面佈局。

@CustomDialog
export default struct PrivacyPolicyDialogBackUp{
    controller: CustomDialogController

    cancel!: () => void
    confirm!: () => void

    build() {
        Column() {
            Text($r('app.string.simple_user_policy')).fontSize(18).fontColor($r('app.color.title_color')).margin({ top: 30, bottom: 19 })

            Scroll(){
                Text(){
                    Span($r('app.string.privacy_policy_start'))
                    Span($r('app.string.user_agreement_two')).fontColor($r('app.color.mainColor')).onClick(() => {
                        this.openWebUrl("/useragreement.html");
                    })
                    Span($r('app.string.and'))
                    Span($r('app.string.privacy_policy_two')).fontColor($r('app.color.mainColor')).onClick(() => {
                        this.openWebUrl("/privacypolicy.html");
                    })
                    Span($r('app.string.simple_privacy_policy'))
                }.fontSize(16).fontColor($r('app.color.body_color')).margin({
                    left:25,
                    right:25
                })
            }.height(120)

            Column(){
                Button($r('app.string.disagree_privacy_policy')).onClick(() => {
                    this.controller.close();
                    this.cancel();
                }).fontColor($r('app.color.other_color')).fontSize(15).backgroundColor(Color.Transparent)

                Button($r('app.string.agree_privacy_policy')).onClick(() => {
                    this.controller.close();
                    this.confirm();
                }).fontColor($r('app.color.white')).fontSize(17)
                    .linearGradient({
                        direction: GradientDirection.Right, colors:[[$r('app.color.start_main_color'),0.0],[$r('app.color.end_main_color'),1.0]]
                    }).width('80%').margin({
                    top:15,bottom:21
                }).borderRadius(24)
            }
        }
    }

    openWebUrl(urlSuffix:string){
        let url= AppConstant.URL+urlSuffix;
        logger.info("url:"+url)
        router.pushUrl({
            url: Pages.WebViewPage,
            params:{
                data1: 'message',
                url: url,  // 傳遞的 URL 引數
            }
        }, router.RouterMode.Single)
    }
}

在元件中建立CustomDialogController例項,指定builder屬性,就是上面寫的內容構造器

privacyPolicyDialog: CustomDialogController = new CustomDialogController({
  builder: PrivacyPolicyDialog({
    cancel:this.onCancel.bind(this),
    confirm:this.onAgree.bind(this)
  }),
  alignment: DialogAlignment.Default,  // 可設定dialog的對齊方式,設定顯示在底部或中間等,預設為底部顯示
  cornerRadius:13,
  autoCancel:false
})

顯示彈窗

this.privacyPolicyDialog.open();

關閉彈窗

this.privacyPolicyDialog.close();

效果圖:

參考官方連結:

https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V2/ts-methods-custom-dialog-box-0000001477981237-V2

載入中彈窗

載入中彈窗彈窗其實就是自定義彈窗實現,只是內容構造器不一樣而已,給Image元件設定animation動畫,無限迴圈圖片

@CustomDialog
export default struct LoadingDialog {
    controller: CustomDialogController

    private loadingText: string|Resource = "載入中..."
    @State angle:number = 10

    aboutToAppear(){
        setTimeout(()=>{
            this.angle = 1440 // 設定一個大的旋轉角度,確保動畫執行
        },100)
    }

    build() {
        Column(){
            Image($r('app.media.icon_loading_3'))
                .width(70)
                .height(70)
                .rotate({angle:this.angle})
                .animation({
                    duration: 5000,
                    curve: Curve.Linear,
                    delay: 0,
                    iterations: -1, // 設定-1表示動畫無限迴圈
                    playMode: PlayMode.Normal
                })


            Text(this.loadingText).fontSize(14).fontColor(0xffffff).margin({top:10})
        }.backgroundColor(0x88000000).borderRadius(10).padding({
            left:20,right:20,top:10,bottom:10
        })
    }
}

效果圖:

原始碼下載:

https://github.com/ansen666/harmony_tools

如果您想第一時間看我的後期文章,掃碼關注公眾號

      安輝程式設計筆記 - 開發技術分享
             掃描二維碼加關注

安輝程式設計筆記

相關文章