響應(yīng)式制作網(wǎng)站建設(shè)線上教育培訓(xùn)機(jī)構(gòu)十大排名
HarmonyOS(二) 初識(shí)ArkTS開(kāi)發(fā)語(yǔ)言(下)之TypeScript入門
聲明式UI基本概念
應(yīng)用界面是由一個(gè)個(gè)頁(yè)面組成,ArkTS是由ArkUI框架提供,用于以聲明式開(kāi)發(fā)范式開(kāi)發(fā)界面的語(yǔ)言。
聲明式UI構(gòu)建頁(yè)面的過(guò)程,其實(shí)是組合組件的過(guò)程,聲明式UI的思想,主要體現(xiàn)在兩個(gè)方面:
- 描述UI的呈現(xiàn)結(jié)果,而不關(guān)心過(guò)程
- 狀態(tài)驅(qū)動(dòng)視圖更新
類似蘋果的SwiftUI中通過(guò)組合視圖View,安卓Jetpack Compose中通過(guò)組合@Composable函數(shù),ArkUI作為HarmonyOS應(yīng)用開(kāi)發(fā)的UI開(kāi)發(fā)框架,其使用ArkTS語(yǔ)言構(gòu)建自定義組件,通過(guò)組合自定義組件完成頁(yè)面的構(gòu)建。
自定義組件的組成
ArkTS通過(guò)struct聲明組件名,并通過(guò)@Component和@Entry裝飾器,來(lái)構(gòu)成一個(gè)自定義組件。
使用@Entry和@Component裝飾的自定義組件作為頁(yè)面的入口,會(huì)在頁(yè)面加載時(shí)首先進(jìn)行渲染。
@Entry
@Component
struct ToDoList {...}
例如ToDoList組件對(duì)應(yīng)如下整個(gè)代辦頁(yè)面。
圖1 ToDoList待辦列表
使用@Component裝飾的自定義組件,如ToDoItem這個(gè)自定義組件則對(duì)應(yīng)如下內(nèi)容,作為頁(yè)面的組成部分。
@Component
struct ToDoItem {...}
圖2 ToDoItem
在自定義組件內(nèi)需要使用build方法來(lái)進(jìn)行UI描述。
@Entry
@Componentstruct ToDoList...build() {...}
}
build方法內(nèi)可以容納內(nèi)置組件和其他自定義組件,如Column和Text都是內(nèi)置組件,由ArkUI框架提供,ToDoItem為自定義組件,需要開(kāi)發(fā)者使用ArkTS自行聲明。
@Entry
@Component
struct ToDoList {...build() {Column(...) {Text(...)...ForEach(...{TodoItem(...)},...)}...}
}
配置屬性與布局
自定義組件的組成使用基礎(chǔ)組件和容器組件等內(nèi)置組件進(jìn)行組合。但有時(shí)內(nèi)置組件的樣式并不能滿足我們的需求,ArkTS提供了屬性方法用于描述界面的樣式。屬性方法支持以下使用方式:
-
常量傳遞
例如使用fontSize(50)來(lái)配置字體大小。
Text('Hello World').fontSize(50)
-
變量傳遞
在組件內(nèi)定義了相應(yīng)的變量后,例如組件內(nèi)部成員變量size,就可以使用this.size方式使用該變量。
Text('Hello World').fontSize(this.size)
-
鏈?zhǔn)秸{(diào)用
在配置多個(gè)屬性時(shí),ArkTS提供了鏈?zhǔn)秸{(diào)用的方式,通過(guò)’.'方式連續(xù)配置。
Text('Hello World').fontSize(this.size).width(100).height(100)
-
表達(dá)式傳遞
屬性中還可以傳入普通表達(dá)式以及三目運(yùn)算表達(dá)式。
Text('Hello World').fontSize(this.size).width(this.count + 100).height(this.count % 2 === 0 ? 100 : 200)
-
內(nèi)置枚舉類型
除此之外,ArkTS中還提供了內(nèi)置枚舉類型,如Color,FontWeight等,例如設(shè)置fontColor改變字體顏色為紅色,并私有fontWeight為加粗。
Text('Hello World').fontSize(this.size).width(this.count + 100).height(this.count % 2 === 0 ? 100 : 200).fontColor(Color.Red).fontWeight(FontWeight.Bold)
對(duì)于有多種組件需要進(jìn)行組合時(shí),容器組件則是描述了這些組件應(yīng)該如何排列的結(jié)果。
ArkUI中的布局容器有很多種,在不同的適用場(chǎng)合選擇不同的布局容器實(shí)現(xiàn),ArkTS使用容器組件采用花括號(hào)語(yǔ)法,內(nèi)部放置UI描述。
這里我們將介紹最基礎(chǔ)的兩個(gè)布局——列布局和行布局。
對(duì)于如下每一項(xiàng)的布局,兩個(gè)元素為橫向排列,選擇Row布局
圖3 Row布局
Row() {Image($r('app.media.ic_default'))...Text(this.content) ...
}
...
類似下圖所示的布局,整體都是從上往下縱向排列,適用的布局方式是Column列布局。
圖4 Column布局
Column() {Text($r('app.string.page_title'))...ForEach(this.totalTasks,(item) => {TodoItem({content:item})},...)}
改變組件狀態(tài)
實(shí)際開(kāi)發(fā)中由于交互,頁(yè)面的內(nèi)容可能需要產(chǎn)生變化,以每一個(gè)ToDoItem為例,其在完成時(shí)的狀態(tài)與未完成時(shí)的展示效果是不一樣的。
圖5 不同狀態(tài)的視圖
聲明式UI的特點(diǎn)就是UI是隨數(shù)據(jù)更改而自動(dòng)刷新的,我們這里定義了一個(gè)類型為boolean的變量isComplete,其被@State裝飾后,框架內(nèi)建立了數(shù)據(jù)和視圖之間的綁定,其值的改變影響UI的顯示。
@State isComplete : boolean = false;
圖6 @State裝飾器的作用
用圓圈和對(duì)勾這樣兩個(gè)圖片,分別來(lái)表示該項(xiàng)是否完成,這部分涉及到內(nèi)容的切換,需要使用條件渲染if / else語(yǔ)法來(lái)進(jìn)行組件的顯示與消失,當(dāng)判斷條件為真時(shí),組件為已完成的狀態(tài),反之則為未完成。
if (this.isComplete) {Image($r('app.media.ic_ok')).objectFit(ImageFit.Contain).width($r('app.float.checkbox_width')).height($r('app.float.checkbox_width')).margin($r('app.float.checkbox_margin'))
} else {Image($r('app.media.ic_default')).objectFit(ImageFit.Contain).width($r('app.float.checkbox_width')).height($r('app.float.checkbox_width')).margin($r('app.float.checkbox_margin'))
}
由于兩個(gè)Image的實(shí)現(xiàn)具有大量重復(fù)代碼,ArkTS提供了@Builder裝飾器,來(lái)修飾一個(gè)函數(shù),快速生成布局內(nèi)容,從而可以避免重復(fù)的UI描述內(nèi)容。這里使用@Bulider聲明了一個(gè)labelIcon的函數(shù),參數(shù)為url,對(duì)應(yīng)要傳給Image的圖片路徑。
@Builder labelIcon(url) {Image(url).objectFit(ImageFit.Contain).width($r('app.float.checkbox_width')).height($r('app.float.checkbox_width')).margin($r('app.float.checkbox_margin'))
}
使用時(shí)只需要使用this關(guān)鍵字訪問(wèn)@Builder裝飾的函數(shù)名,即可快速創(chuàng)建布局。
if (this.isComplete) {this.labelIcon($r('app.media.ic_ok'))
} else {this.labelIcon($r('app.media.ic_default'))
}
為了讓待辦項(xiàng)帶給用戶的體驗(yàn)更符合已完成的效果,給內(nèi)容的字體也增加了相應(yīng)的樣式變化,這里使用了三目運(yùn)算符來(lái)根據(jù)狀態(tài)變化修改其透明度和文字樣式,如opacity是控制透明度,decoration是文字是否有劃線。通過(guò)isComplete的值來(lái)控制其變化。
Text(this.content)....opacity(this.isComplete ? CommonConstants.OPACITY_COMPLETED : CommonConstants.OPACITY_DEFAULT).decoration({ type: this.isComplete ? TextDecorationType.LineThrough : TextDecorationType.None })
最后,為了實(shí)現(xiàn)與用戶交互的效果,在組件上添加了onClick點(diǎn)擊事件,當(dāng)用戶點(diǎn)擊該待辦項(xiàng)時(shí),數(shù)據(jù)isComplete的更改就能夠觸發(fā)UI的更新。
@Component
struct ToDoItem {@State isComplete : boolean = false;@Builder labelIcon(icon) {...}...build() {Row() {if (this.isComplete) {this.labelIcon($r('app.media.ic_ok'))} else {this.labelIcon($r('app.media.ic_default'))}... }....onClick(() => {this.isComplete= !this.isComplete;})}
}
循環(huán)渲染列表數(shù)據(jù)
剛剛只是完成了一個(gè)ToDoItem組件的開(kāi)發(fā),當(dāng)我們有多條待辦數(shù)據(jù)需要顯示在頁(yè)面時(shí),就需要使用到ForEach循環(huán)渲染語(yǔ)法。
例如這里我們有五條待辦數(shù)據(jù)需要展示在頁(yè)面上。
total_Tasks:Array<string> = ['早起晨練','準(zhǔn)備早餐','閱讀名著','學(xué)習(xí)ArkTS','看劇放松'
]
ForEach基本使用中,只需要了解要渲染的數(shù)據(jù)以及要生成的UI內(nèi)容兩個(gè)部分,例如這里要渲染的數(shù)組為以上的五條待辦事項(xiàng),要渲染的內(nèi)容是ToDoItem這個(gè)自定義組件,也可以是其他內(nèi)置組件。
圖7 ForEach基本使用
ToDoItem這個(gè)自定義組件中,每一個(gè)ToDoItem要顯示的文本參數(shù)content需要外部傳入,參數(shù)傳遞使用花括號(hào)的形式,用content接受數(shù)組內(nèi)的內(nèi)容項(xiàng)item。
最終完成的代碼及其效果如下。
@Entry
@Component
struct ToDoList {...build() {Row() {Column() {Text(...)...ForEach(this.totalTasks,(item) => {TodoItem({content:item})},...)}.width('100%')}.height('100%')}}
圖8 ToDoList頁(yè)面