這是一個運(yùn)動記錄的應(yīng)用,主要用于管理健康記錄運(yùn)動??梢蕴砑舆\(yùn)動信息,包括運(yùn)動名稱、運(yùn)動時長,并自動計算消耗的卡路里,在記錄頁面可以查看所添加的運(yùn)動記錄。

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


正文
一、總體布局設(shè)置
從效果圖來對彈窗內(nèi)容作布局,頂部是兩個按鈕“取消”“確定”和一個彈窗標(biāo)題,中部是運(yùn)動項(xiàng)的數(shù)據(jù)(包括圖片、名稱、單位消耗的熱量、時間的輸入框及自動計算得出的總值),底部是一個簡易輸入器(0-9的輸入及刪除)。三部分是縱向排布,頂部是橫向布局,底部的輸入器使用了柵格布局。
自定義彈窗組件要用**@CustomDialog** 修飾,我將彈窗組件命名為Record,其基本布局代碼框架如下:
@CustomDialog
struct Record {
private controller: CustomDialogController
@State time: string = '0'
@State sum: number = 0
private title: string = '添加運(yùn)動'
private sportsItem: SportsData //自定義的類
//其他定義的變量...
//運(yùn)動數(shù)據(jù)項(xiàng)的布局
@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('確認(rèn)').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%')
}
}
二、子布局設(shè)置和點(diǎn)擊事件的設(shè)置
由于運(yùn)動數(shù)據(jù)項(xiàng)的數(shù)據(jù)在原demo中是根據(jù)點(diǎn)擊的列表項(xiàng),來傳參顯示相應(yīng)的圖片及名稱,因此讀者可以使用靜態(tài)數(shù)據(jù)來調(diào)試此自定義彈窗組件。代碼部分如下:
@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%')
}
對于輸入器部分,由于在“添加記錄”時,“刪除記錄”按鍵無響應(yīng),于是定義變量mode,區(qū)分增加記錄和修改記錄。
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循環(huán)渲染布局,根據(jù)按鍵類型定義相應(yīng)的點(diǎn)擊事件。若是字符串類型且長度為1的,則為輸入(即字符串拼接),定義輸入范圍為0-999,每次點(diǎn)擊都調(diào)用calculate(),這是計算總值的函數(shù),并實(shí)時顯示計算結(jié)果。若按鍵類型是圖片,則實(shí)現(xiàn)回刪的點(diǎn)擊事件,同樣也會調(diào)用calculate()。點(diǎn)擊“刪除記錄”時,會彈窗確認(rèn)。代碼如下:
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: '確認(rèn)刪除這條運(yùn)動記錄嗎?',
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%')
}
}
三、總體布局的點(diǎn)擊事件及調(diào)用該自定義彈窗組件
1、確認(rèn)按鍵的點(diǎn)擊事件
因?yàn)樯婕叭肿兞康绕渌M件的代碼,因此筆者簡單帶過業(yè)務(wù)邏輯的實(shí)現(xiàn)。代碼如下:
Button('確認(rèn)').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) {//添加記錄的實(shí)現(xiàn)代碼,筆者是通過push數(shù)據(jù)進(jìn)數(shù)組變量來實(shí)現(xiàn)的。
}
else if (this.mode == 1) {
//修改(更新)記錄的實(shí)現(xiàn)代碼,筆者是對對應(yīng)索引的數(shù)組值作更新來實(shí)現(xiàn)的。
}
this.controller.close()
}
})
}.width('100%').height(50)
2、調(diào)用自定義彈窗組件
主要代碼如下:
@Component
export struct SportsGridItem {
private sportsItem: SportsData
private controller: CustomDialogController
aboutToAppear() {
this.controller = new CustomDialogController({
builder: Record({ sportsItem: this.sportsItem }),
alignment: DialogAlignment.Center
})
}
結(jié)語
以上就是本次的小分享啦!
??想了解更多關(guān)于開源的內(nèi)容,請訪問:??
??51CTO 開源基礎(chǔ)軟件社區(qū)??
??https://ost.51cto.com??。