OpenHarmony應(yīng)用開發(fā)之自定義彈窗
想了解更多關(guān)于開源的內(nèi)容,請?jiān)L問:
應(yīng)用場景
在應(yīng)用的使用和開發(fā)中,彈窗是一個(gè)很常見的場景,自定義彈窗又因?yàn)闃O高的自由度得以廣泛應(yīng)用。本文以橘子購物中一個(gè)應(yīng)用更新提示的彈窗介紹OpenHarmony的自定義彈窗。
OpenHarmony應(yīng)用開發(fā)之自定義彈窗-開源基礎(chǔ)軟件社區(qū)
接口
自定義彈窗官方文檔:自定義彈窗-彈窗-全局UI方法-組件參考(基于ArkTS的聲明式開發(fā)范式)-ArkTS API參考-HarmonyOS應(yīng)用開發(fā)。
CustomDialogController是自定義彈窗對(duì)應(yīng)的接口,詳細(xì)介紹如下:
CustomDialogController(value:{builder: CustomDialog, cancel?: () => void, autoCancel?: boolean, alignment?: DialogAlignment,
offset?: Offset, customStyle?: boolean, gridCount?: number, maskColor?: ResourceColor,
openAnimation?: AnimateParam, closeAnimation?: AnimateParam})
參數(shù):
參數(shù)名 | 參數(shù)類型 | 必填 | 參數(shù)描述 |
builder | CustomDialog | 是 | 自定義彈窗內(nèi)容構(gòu)造器。 |
cancel | () => void | 否 | 點(diǎn)擊遮障層退出時(shí)的回調(diào)。 |
autoCancel | boolean | 否 | 是否允許點(diǎn)擊遮障層退出。默認(rèn)值:true |
alignment | 否 | 彈窗在豎直方向上的對(duì)齊方式。默認(rèn)值:DialogAlignment.Default | |
offset | 否 | 彈窗相對(duì)alignment所在位置的偏移量。 | |
customStyle | boolean | 否 | 彈窗容器樣式是否自定義。默認(rèn)值:false,彈窗容器的寬度根據(jù)柵格系統(tǒng)自適應(yīng), 不跟隨子節(jié)點(diǎn);高度自適應(yīng)子節(jié)點(diǎn),最大為窗口高度的90%;圓角為24vp。 |
gridCount8+ | number | 否 | 彈窗寬度占柵格寬度的個(gè)數(shù)。默認(rèn)為按照窗口大小自適應(yīng),異常值按默認(rèn)值處理, 最大柵格數(shù)為系統(tǒng)最大柵格數(shù)。 |
這其中最重要的就是builder,我們需要自己實(shí)現(xiàn)一個(gè)構(gòu)造器,也就是這個(gè)彈窗的頁面。
具體實(shí)現(xiàn)
定義CustomDialogController
首先,我們需要定義一個(gè)CustomDialogController:
UpdateDialogController: CustomDialogController = new CustomDialogController({
builder: UpdateDialog(),
customStyle: true
})
這個(gè)CustomDialogController就代表彈窗,UpdateDialog()是彈窗的具體實(shí)現(xiàn),customStyle為ture就表示彈窗樣式可以自定義。
設(shè)置調(diào)用時(shí)機(jī)
在這個(gè)場景中,我們想要每次打開應(yīng)用的時(shí)候彈窗,其他時(shí)候不彈窗,我們需要在首頁組件的aboutToAppear中加入以下代碼:
aboutToAppear() {
if(AppStorage.Get('nowIndex') === undefined || AppStorage.Get('nowIndex') === 0){
this.UpdateDialogController.open()
}
}
aboutToAppear函數(shù)的調(diào)用時(shí)機(jī)是創(chuàng)建自定義組件的新實(shí)例后,執(zhí)行其build()函數(shù)之前,所以在首頁組件的aboutToAppear加入CustomDialogController的打開開邏輯可使彈窗僅在應(yīng)用打開的時(shí)候觸發(fā)。
aboutToAppear參考文檔:自定義組件的生命周期-組件參考(基于ArkTS的聲明式開發(fā)范式)-ArkTS API參考-HarmonyOS應(yīng)用開發(fā)。
實(shí)現(xiàn)builder實(shí)例
實(shí)現(xiàn)實(shí)例可以直接在builder后面直接實(shí)現(xiàn),也可以定義在其他文件中,然后通過調(diào)用的方式獲取,本文以調(diào)用方式實(shí)現(xiàn)。
實(shí)例組件的定義前需加export才能暴露出去:
export struct UpdateDialog {}
彈窗上所需的數(shù)據(jù)和獲取也需要在在此處定義:
@CustomDialog
export struct UpdateDialog {
@State currentVersion: string = ''
@State richTextData: string = ''
@State lastVersion: string = ''
@State updateContent: string = ''
private context?: AbilityContext
private customDialogController?: CustomDialogController
async aboutToAppear() {
this.context = getContext(this) as AbilityContext
this.richTextData = await dialogFeature.getRichTextData(this.context)
Logger.info(TAG, `this.richTextData = ${this.richTextData}`)
await this.getData()
}
async getData() {
try {
this.currentVersion = await dialogFeature.getCurrentVersion()
let requestResponseContent: RequestResponseContent = await dialogFeature.getLastVersion()
if (requestResponseContent.content === null || requestResponseContent.content === undefined) {
return
}
this.updateContent = requestResponseContent.content
if (requestResponseContent.versionName === null || requestResponseContent.versionName === undefined) {
return
}
this.lastVersion = requestResponseContent.versionName
} catch (err) {
Logger.info(TAG, `getApplicationVersion is fail`)
}
}
...
以上是應(yīng)用升級(jí)所需的數(shù)據(jù)結(jié)構(gòu)及部分?jǐn)?shù)據(jù)獲取。
彈窗具體實(shí)現(xiàn)
自定義彈窗的實(shí)現(xiàn)就是在原頁面的基礎(chǔ)上再加一層頁面,頁面內(nèi)容自定義。
彈窗頁面我們可以通過stack組件實(shí)現(xiàn),stack組件會(huì)使容器內(nèi)的子組件堆疊布局,使用stack的好處是可以添加一層遮罩效果。
Stack() {
// mask 遮罩層
Column()
.width('100%')
.height('100%')
.backgroundColor('#000000')
.opacity(.4)
...
以上代碼在stack的第一層設(shè)置了backgroundColor和opacity屬性,這樣會(huì)產(chǎn)生如開始示意圖的遮罩效果。
需要注意的是,需要在取消按鈕的調(diào)用函數(shù)中關(guān)閉彈窗,具體代碼如下:
Button($r('app.string.cancel'))
.onClick(() => {
this.customDialogController.close()
})
彈窗完整代碼:
build() {
Stack() {
// mask 遮罩層
Column()
.width('100%')
.height('100%')
.backgroundColor('#000000')
.opacity(.4)
Column() {
Stack({ alignContent: Alignment.TopStart }) {
Text($r('app.string.update_title'))
.fontSize(30)
.fontColor('#FFFFFF')
.fontWeight(500)
.margin({ top: 70, left: 76 })
Text(`V${(this.lastVersion || updateData.versionName)}`)
.fontSize(16)
.backgroundColor('#FFFFFF')
.textAlign(TextAlign.Center)
.fontColor('#E9304E')
.borderRadius(20)
.width(80)
.aspectRatio(2.8)
.margin({ top: 110, left: 76 })
Column() {
// 富文本容器
Scroll() {
Column() {
if (this.richTextData) {
RichText((this.updateContent || this.richTextData))
.width('100%')
.height('100%')
}
}
.width('100%')
}
.height(200)
Row() {
Button($r('app.string.cancel'))
.commonButtonStyle()
.fontSize(20)
.margin({ left: 10 })
.fontColor('#E92F4F')
.backgroundColor('rgba(0,0,0,0.05)')
.margin({ right: 10 })
.onClick(() => {
this.customDialogController.close()
})
.key("cancel")
Button($r('app.string.update_now'))
.commonButtonStyle()
.fontSize(20)
.margin({ right: 10 })
.fontColor('#FFFFFF')
.backgroundColor('#E92F4F')
.margin({ left: 10 })
.onClick(() => {
this.customDialogController.close()
})
.key("Now")
}
.margin({ top: 30 })
}
.width('100%')
.padding({ left: 25, right: 25 })
.margin({ top: 230 })
}
.height(600)
.width('100%')
.backgroundImage($r('app.media.update'), ImageRepeat.NoRepeat)
.backgroundImageSize(ImageSize.Contain)
}
.width(480)
.padding({ left: 16, right: 16 })
}
.width('100%')
.height('100%')
}
以上是彈窗完整代碼,需要注意的是,本例并未實(shí)現(xiàn)應(yīng)用升級(jí)的具體邏輯,所以升級(jí)按鈕的操作也是關(guān)閉彈窗。