
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區??
??https://ost.51cto.com??。
前言
在參加了"HarmonyOS ArkUI入門訓練營——健康生活實戰"后,了解并學習了聲明式UI開發框架及組件用法,本文是對筆者結營作品中的自定義彈窗組件作一個小分享。
概述
這是一個運動記錄的應用,主要用于管理健康記錄運動。可以添加運動信息,包括運動名稱、運動時長,并自動計算消耗的卡路里,在記錄頁面可以查看所添加的運動記錄。
自定義彈窗組件運行效果圖如下:


正文
一、總體布局設置
從效果圖來對彈窗內容作布局,頂部是兩個按鈕“取消”“確定”和一個彈窗標題,中部是運動項的數據(包括圖片、名稱、單位消耗的熱量、時間的輸入框及自動計算得出的總值),底部是一個簡易輸入器(0-9的輸入及刪除)。三部分是縱向排布,頂部是橫向布局,底部的輸入器使用了柵格布局。
自定義彈窗組件要用**@CustomDialog** 修飾,我將彈窗組件命名為Record,其基本布局代碼框架如下:
@CustomDialog
struct Record {
private controller: CustomDialogController
@State time: string = '0'
@State sum: number = 0
private title: string = '添加運動'
private sportsItem: SportsData //自定義的類
//其他定義的變量...
//運動數據項的布局
@Builder RecordItem(image: Resource, name: string, value: number) {
}
//輸入器的布局
@Builder valueInput() {
}
//彈窗的總布局
build() {
Column() {
Row() {
Button('取消').fontSize(16).fontColor('#3ECF69').width(70).height(25).backgroundColor(Color.White)
.onClick(() => {
this.controller.close()
})
Blank().flexGrow(1)
Text(this.title).fontSize(22).fontWeight(400).width(100)
Blank().flexGrow(1)
Button('確認').fontSize(16).fontColor('#3ECF69').width(70).height(25).backgroundColor(Color.White)
.onClick(() => {
})
}.width('100%').height(50)
Divider().width('100%').vertical(false).strokeWidth(0.5)
this.RecordItem(this.sportsItem.image, this.sportsItem.name, this.sportsItem.value)
Divider().width('100%').vertical(false).strokeWidth(0.5)
Row() {
Blank().flexGrow(100)
Row() {
Text(this.time).fontColor('#E14843').fontSize(28).margin({ right: 3 })
Text('分鐘').fontSize(17)
}.width(100)
Blank().flexGrow(1)
Text(this.sum + '千卡').fontColor(Color.Gray).fontSize(17).width(100).textAlign(TextAlign.End).padding(5)
}.width('100%').margin({ top: 12, bottom: 12 })
Divider().width('100%').vertical(false).strokeWidth(0.5)
this.valueInput() //輸入器
}.width('82%')
}
}
二、子布局設置和點擊事件的設置
由于運動數據項的數據在原demo中是根據點擊的列表項,來傳參顯示相應的圖片及名稱,因此讀者可以使用靜態數據來調試此自定義彈窗組件。代碼部分如下:
@Builder RecordItem(image: Resource, name: string, value: number) {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image(image).width(60).height(60).borderRadius(30).objectFit(ImageFit.Contain).backgroundColor('#ffffff').margin(5)
Text(name).fontSize(17).margin(5)
Row({ space: 6 }) {
Text(value.toString()).fontColor('#EC7143').fontSize(19)
Text('千卡/60分鐘').fontColor(Color.Gray).fontSize(17)
}.margin(5)
}.height(170).backgroundColor('#F5F5F5').width('100%')
}
對于輸入器部分,由于在“添加記錄”時,“刪除記錄”按鍵無響應,于是定義變量mode,區分增加記錄和修改記錄。
private mode: number = 0 //0:添加,1:修改
private Valueinput: any[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '刪除記錄', '0', $r('app.media.Back')]
接著定義4行3列的柵格布局,用ForEach循環渲染布局,根據按鍵類型定義相應的點擊事件。若是字符串類型且長度為1的,則為輸入(即字符串拼接),定義輸入范圍為0-999,每次點擊都調用calculate(),這是計算總值的函數,并實時顯示計算結果。若按鍵類型是圖片,則實現回刪的點擊事件,同樣也會調用calculate()。點擊“刪除記錄”時,會彈窗確認。代碼如下:
calculate() {
if (this.time.length != 0) {
this.sum = Math.round(parseInt(this.time) * this.sportsItem.value / 60)
} else {
this.sum = 0
}
}
@Builder valueInput() {
Column() {
Grid() {
ForEach(this.Valueinput, (item: any) => {
GridItem() {
if (typeof (item) == 'string') {
Text(item)
.fontSize(20)
.fontWeight(500)
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
.onClick(() => {
if(item.length<2){
if (this.time == '0') {
this.time = item
}
else if (parseInt(this.time) < 999 && parseInt(this.time + item) < 999) {
this.time = this.time + item
}
else {
this.time = '999'
}
this.calculate()
}
else{
if(this.mode==1){
AlertDialog.show(
{
message: '確認刪除這條運動記錄嗎?',
primaryButton: {
value: '取消',
action: () => {
}
},
secondaryButton: {
value: '確定',
action: () => {
//刪除邏輯...
this.controller.close()
}
},
cancel: () => {
}
}
)
}
}
})
} else if (typeof (item) == 'object') {
Image(item).width(20).aspectRatio(1).objectFit(ImageFit.Contain)
.onClick(() => {
if (this.time.length > 1) {
this.time = this.time.substring(0, this.time.length - 1)
}
else if (this.time.length == 1) {
this.time = '0'
}
this.calculate()
})
}
}
})
}
.backgroundColor(Color.White)
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr')
.columnsGap(0)
.rowsGap(0)
.width('100%')
.height('35%')
}
}
三、總體布局的點擊事件及調用該自定義彈窗組件
1、確認按鍵的點擊事件
因為涉及全局變量等其他組件的代碼,因此筆者簡單帶過業務邏輯的實現。代碼如下:
Button('確認').fontSize(16).fontColor('#3ECF69').width(70).height(25).backgroundColor(Color.White)
.onClick(() => {
if (this.time == '0') {
prompt.showToast({ message: '輸入不能為零', duration: 1000 })
}
else {
if (this.mode == 0) {//添加記錄的實現代碼,筆者是通過push數據進數組變量來實現的。
}
else if (this.mode == 1) {
//修改(更新)記錄的實現代碼,筆者是對對應索引的數組值作更新來實現的。
}
this.controller.close()
}
})
}.width('100%').height(50)
2、調用自定義彈窗組件
主要代碼如下:
@Component
export struct SportsGridItem {
private sportsItem: SportsData
private controller: CustomDialogController
aboutToAppear() {
this.controller = new CustomDialogController({
builder: Record({ sportsItem: this.sportsItem }),
alignment: DialogAlignment.Center
})
}
結語
以上就是本次的小分享啦!
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區??
??https://ost.51cto.com??。