前言
鴻蒙官方的文檔寫得很詳細,也有Demo示例代碼脯厨,但從《構(gòu)建更加豐富的界面》這個章節(jié)起铅祸,大段大段地省略重要內(nèi)容,包括但不限于“在代碼片段里寫一大堆省略號”合武、“只貼代碼片段不說貼在什么位置”临梗、“對另一個先前教學中沒有提到過的內(nèi)容只字不提或一筆帶過”等情況,導致學習時不得不去翻文檔看Demo自己試錯稼跳。而Demo也做得非常復雜盟庞,根本不適合初學者閱讀。
這個《細枝末節(jié)》系列算是作為官方教學的補充汤善,給初學者看的什猖,專門補充官方教學文檔沒說的細節(jié)。
本文是對《構(gòu)建更加豐富的頁面》中《自定義窗口》部分的補充
本文對應的API版本是9
開發(fā)工具版本
DevEco Studio 3.1.1 Release
Build Version: 3.1.0.501, built on June 20, 2023
Build #DS-223.8617.56.36.310501
Runtime version: 17.0.6+10-b829.5 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 10 10.0
GC: G1 Young Generation, G1 Old Generation
Memory: 1024M
Cores: 16
Registry:
external.system.auto.import.disabled=true
Non-Bundled Plugins:
com.intellij.marketplace (223.8617.59)
izhangzhihao.rainbow.brackets (2023.3.7)
實現(xiàn)效果
原文的自定義窗口寫得非常復雜红淡,甚至用到了先前教程未提及的數(shù)據(jù)部分不狮。
本文直接換用一個簡單的例子虹蓄。我們來實現(xiàn)第一部分《管理組件狀態(tài)》那個界面下面的“添加子目標”彈窗煤墙。
編寫自定義彈窗類
創(chuàng)建一個新文件顺囊,我這里起名叫OkCancelInputDialog
然后聲明如下:
@CustomDialog
export default struct OkCancelInputDialog {
build() {
}
}
@CustomDialog
這個注解表示這個控件是對話框
export default
如果不寫這個的話箕般,無法被其他文件調(diào)用
接下來我們在build
里面寫界面,先分析一下效果圖:
一個輸入框TextInput
搁吓,兩個按鈕Button
水平排列抹缕,輸入框和按鈕豎直排列安接。
最外層使用Column
排列輸入框和按鈕俊嗽,兩個按鈕使用Row
包起來橫排雾家,按鈕中間用Blank
填充空隙。
補全界面代碼如下:
build() {
Column() {
TextInput({ placeholder: '請輸入內(nèi)容' }) //輸入框
.onChange((str) => {
//TODO:更新輸入內(nèi)容
})
.margin({ left: 16, right: 16 })
Row() {
Button("取消", { type: ButtonType.Capsule })
.onClick(() => {
//TODO:點擊取消按鈕的事件
})
.backgroundColor(Color.White)
.fontColor(Color.Blue)
.width("45%")
Blank()
Button("確定", { type: ButtonType.Capsule })
.onClick(() => {
//TODO:點擊確定按鈕的事件
})
.backgroundColor(Color.Blue)
.fontColor(Color.White)
.width("45%")
}
.width('100%')
.margin({ top: 16, bottom: 16, left: 32, right: 32 })
}
.margin({ left: 16, right: 16 })
.padding({ top: 24, bottom: 24 })
}
然后再創(chuàng)建一個變量來保存輸入的值绍豁,創(chuàng)建兩個方法對應兩個按鈕的點擊事件芯咧。最終這個類的代碼如下:
@CustomDialog
export default struct OkCancelInputDialog {
inputValue: string//存放輸入內(nèi)容的變量
controller: CustomDialogController
cancel: () => void//取消按鈕對應事件
confirm: (string) => void//確定按鈕對應事件
build() {
Column() {
TextInput({ placeholder: '請輸入內(nèi)容' }) //輸入框
.onChange((str) => {
this.inputValue = str
})
.margin({ left: 16, right: 16 })
Row() {
Button("取消", { type: ButtonType.Capsule })
.onClick(() => {
this.cancel();
})
.backgroundColor(Color.White)
.fontColor(Color.Blue)
.width("45%")
Blank()
Button("確定", { type: ButtonType.Capsule })
.onClick(() => {
this.confirm(this.inputValue);
})
.backgroundColor(Color.Blue)
.fontColor(Color.White)
.width("45%")
}
.width('100%')
.margin({ top: 16, bottom: 16, left: 32, right: 32 })
}
.margin({ left: 16, right: 16 })
.padding({ top: 24, bottom: 24 })
}
}
調(diào)用彈窗
來到要調(diào)用彈窗的界面,在文件頭import
自定義彈窗類竹揍,然后聲明一個CustomDialogController
(這個寫法我是照著Demo抄的敬飒,我目前還不知道Controller
到底是什么,只知道這玩意可以操作自定義彈窗對象芬位。猜測是類似于 Android 的 Service 和 Binder 的關系无拗。)
import OkCancelInputDialog from './OkCancelInputDialog';
@Entry
@Component
struct Index {
dialogController: CustomDialogController = new CustomDialogController({
builder: OkCancelInputDialog({
confirm: (str): void => this.onAccept(str),
cancel: (): void => this.onCancel(),
})
});
build() {
Column() {
//點擊顯示彈窗
Button('點擊添加', { type: ButtonType.Capsule, stateEffect: true })
.borderRadius(8)
.backgroundColor("#ff0078d2")
.onClick(() => {
if (this.dialogController != undefined) {
this.dialogController.open()//顯示彈窗
}
})
.fontSize(20)
.padding({ left: 32, right: 32, top: 16, bottom: 16 })
.margin({ bottom: 32 })
}
.width('100%')
.height('100%')
.backgroundColor("#ffe0e0e0")
}
onAccept(str) {
console.log(str); //打印輸入的值
this.dialogController.close();//關閉彈窗
}
onCancel() {
this.dialogController.close();//關閉彈窗
}
}
這里的confirm
和cancel
是自定義彈窗類中定義的函數(shù)名,在自定義彈窗類中昧碉,括號里的 string 是參數(shù)的類型英染。此處調(diào)用的地方,括號里的 str 是參數(shù)的名字被饿。有點類似于 Android 的 Listener 的寫法四康。
注意這里不能這樣寫
cancel:this.oncancel//編譯能過,但會報運行時異常狭握。
或者
cancel:this.oncancel()//編譯能過闪金,但會報運行時異常。
也可以不引用一個函數(shù)论颅,而是直接寫函數(shù)體
cancel: (): void => this.dialogController.close()//關閉彈窗