HarmonyOS開(kāi)發(fā)學(xué)習(xí)筆記
基本步驟
- 開(kāi)發(fā)環(huán)境搭建 按照官網(wǎng)步驟
- 語(yǔ)言選擇 官方建議選擇arkTs(TypeScript的超集)
- 官方開(kāi)發(fā) 參考指南 入門(mén)必讀
- 官方開(kāi)發(fā) 參考api 實(shí)戰(zhàn)必讀
HarmonyOS實(shí)戰(zhàn)所需基礎(chǔ)能力
- 頁(yè)面布局能力
- 頁(yè)面之間的數(shù)據(jù)通信能力(Ability和page; Ability和Ability; page和page)
- 數(shù)據(jù)存儲(chǔ)和讀取能力
- 網(wǎng)絡(luò)請(qǐng)求能力
- 權(quán)限管理能力
- 媒體播放能力
- 通知管理能力
- 文件管理能力
- web接入交互能力
基于ArkTs應(yīng)用(Stage模型)
- 工程目錄結(jié)構(gòu)
- AppScope > app.json5:應(yīng)用的全局配置信息码荔。
- entry:HarmonyOS工程模塊,編譯構(gòu)建生成一個(gè)HAP包该面。
- src > main > ets:用于存放ArkTS源碼明吩。
- src > main > ets > entryability:應(yīng)用/服務(wù)的入口怎炊。
- src > main > ets > pages:應(yīng)用/服務(wù)包含的頁(yè)面右莱。
- src > main > resources:用于存放應(yīng)用/服務(wù)所用到的資源文件救拉,如圖形、多媒體腐缤、字符串捌归、布局文件等。關(guān)于資源文件詳見(jiàn)資源分類與訪問(wèn)岭粤。
- src > main > resources > profile > main_pages.json: 配置頁(yè)面路由
- src > main > module.json5:Stage模型模塊配置文件惜索。主要包含HAP包的配置信息、應(yīng)用/服務(wù)在具體設(shè)備上的配置信息以及應(yīng)用/服務(wù)的全局配置信息剃浇。具體的配置文件說(shuō)明巾兆,詳見(jiàn)module.json5配置文件
- build-profile.json5:當(dāng)前的模塊信息、編譯信息配置項(xiàng)偿渡,包括buildOption臼寄、targets配置等。其中targets中可配置當(dāng)前運(yùn)行環(huán)境溜宽,默認(rèn)為HarmonyOS。
- hvigorfile.ts:模塊級(jí)編譯構(gòu)建任務(wù)腳本质帅,開(kāi)發(fā)者可以自定義相關(guān)任務(wù)和代碼實(shí)現(xiàn)适揉。
- oh_modules:用于存放三方庫(kù)依賴信息留攒。關(guān)于原npm工程適配ohpm操作,請(qǐng)參考歷史工程遷移嫉嘀。
- build-profile.json5:應(yīng)用級(jí)配置信息炼邀,包括簽名、產(chǎn)品配置等剪侮。
- hvigorfile.ts:應(yīng)用級(jí)編譯構(gòu)建任務(wù)腳本拭宁。
HarmonyOS開(kāi)發(fā)中@Entry @Component @State作用
-
@Entry
:這個(gè)注解在自定義組件時(shí)使用,表示該自定義組件為入口組件瓣俯。 -
@Component
:這個(gè)注解在HarmonyOS的UI框架中杰标,表示一個(gè)組件。Component類位于ohos.agp.components包中彩匕,直接派生自java.lang.Object腔剂,并且是HarmonyOS中所有界面組件的直接或間接父類。每一個(gè)組件在屏幕上占用一個(gè)矩形區(qū)域驼仪,在這個(gè)區(qū)域中對(duì)繪制和事件處理做出響應(yīng)掸犬。 -
@State
:這個(gè)注解在組件中定義狀態(tài)變量。狀態(tài)變量變化會(huì)觸發(fā)UI刷新绪爸。它具有以下特征:
支持多種類型:允許class湾碎、number、boolean奠货、string強(qiáng)類型的按值和按引用類型胜茧。允許這些強(qiáng)類型構(gòu)成的數(shù)組,即Array<class>仇味、Array<string>呻顽、Array<boolean>、Array<number>丹墨。不允許object和any廊遍。
支持多實(shí)例:組件不同實(shí)例的內(nèi)部狀態(tài)數(shù)據(jù)獨(dú)立。
內(nèi)部私有:標(biāo)記為@State的屬性是私有變量贩挣,只能在組件內(nèi)訪問(wèn)喉前。
需要本地初始化:必須為所有@State變量分配初始值,將變量保持未初始化可能導(dǎo)致框架行為未定義王财。
創(chuàng)建自定義組件時(shí)支持通過(guò)狀態(tài)變量名設(shè)置初始值:在創(chuàng)建組件實(shí)例時(shí)卵迂,可以通過(guò)變量名顯式指定@State狀態(tài)屬性的初始值。
在HarmonyOS開(kāi)發(fā)中Component中@Builder 和build()作用是否一樣
在HarmonyOS的Component中绒净,@Builder和build()的作用并不完全相同见咒。
@Builder
是一種裝飾器,用于修飾函數(shù)挂疆,以指示該函數(shù)是一個(gè)自定義構(gòu)建函數(shù)改览。被@Builder裝飾的函數(shù)需要遵循build()函數(shù)語(yǔ)法規(guī)則下翎,可以將重復(fù)使用的UI元素抽象成一個(gè)方法,然后在build方法中調(diào)用宝当。通過(guò)使用@Builder裝飾器视事,開(kāi)發(fā)者可以更方便地復(fù)用UI元素,簡(jiǎn)化代碼量庆揩。
而build()
函數(shù)是Component中一個(gè)重要的方法俐东,用于構(gòu)建UI界面。在build()函數(shù)中订晌,開(kāi)發(fā)者可以通過(guò)調(diào)用@Builder裝飾的函數(shù)來(lái)復(fù)用UI元素虏辫,也可以在build()函數(shù)中編寫(xiě)其他的UI構(gòu)建邏輯。因此腾仅,build()函數(shù)和@Builder裝飾器是緊密相關(guān)的乒裆,但并不是相同的概念。
綜上所述推励,@Builder和build()在HarmonyOS的Component中都是重要的開(kāi)發(fā)工具鹤耍,但它們的作用略有不同。@Builder用于定義自定義構(gòu)建函數(shù)验辞,而build()函數(shù)則用于構(gòu)建UI界面稿黄。
HarmonyOS中其它一些常用的裝飾器
-
@Builder/@BuilderParam
:特殊的封裝UI描述的方法,細(xì)粒度的封裝和復(fù)用UI描述跌造。 -
@Extend/@Style
:擴(kuò)展內(nèi)置組件和封裝屬性樣式杆怕,更靈活地組合內(nèi)置組件。 -
stateStyles
:多態(tài)樣式壳贪,可以依據(jù)組件的內(nèi)部狀態(tài)的不同陵珍,設(shè)置不同樣式。
HarmonyOS中Component中幾個(gè)常用的生命周期方法
-
aboutToAppear
組件即將出現(xiàn)時(shí)回調(diào)該接口违施,具體時(shí)機(jī)為在創(chuàng)建自定義組件的新實(shí)例后互纯,在執(zhí)行其build()函數(shù)之前執(zhí)行。 組件生命周期方法 -
aboutToDisappear
在自定義組件即將析構(gòu)銷毀時(shí)執(zhí)行磕蒲。 組件生命周期方法
HarmonyOS中被@Entry裝飾的組件生命周期
-
onPageShow
頁(yè)面每次顯示時(shí)觸發(fā)留潦。 頁(yè)面生命周期方法 -
onPageHide
頁(yè)面每次隱藏時(shí)觸發(fā)一次。 頁(yè)面生命周期方法 -
onBackPress
當(dāng)用戶點(diǎn)擊返回按鈕時(shí)觸發(fā)辣往。頁(yè)面生命周期方法
HarmonyOS開(kāi)發(fā)所需ArkTs基本語(yǔ)法參考文檔
聲明式ui描述
- 創(chuàng)建組件
-
無(wú)參數(shù)
如果組件的接口定義沒(méi)有包含必選構(gòu)造參數(shù)兔院,則組件后面的“()”不需要配置任何內(nèi)容。例如站削,Divider組件不包含構(gòu)造參數(shù):Column() { Text('item 1') Divider() Text('item 2') }
-
有參數(shù)
如果組件的接口定義包含構(gòu)造參數(shù)坊萝,則在組件后面的“()”配置相應(yīng)參數(shù)。- Image組件的必選參數(shù)src。
Image('https://xyz/test.jpg')
- Text組件的非必選參數(shù)content屹堰。
// string類型的參數(shù) Text('test') // $r形式引入應(yīng)用資源肛冶,可應(yīng)用于多語(yǔ)言場(chǎng)景 Text($r('app.string.title_value')) // 無(wú)參數(shù)形式 Text()
- 變量或表達(dá)式也可以用于參數(shù)賦值街氢,其中表達(dá)式返回的結(jié)果類型必須滿足參數(shù)類型要求扯键。
例如,設(shè)置變量或表達(dá)式來(lái)構(gòu)造Image和Text組件的參數(shù)珊肃。Image(this.imagePath) Image('https://' + this.imageUrl) Text(`count: ${this.count}`)
- Image組件的必選參數(shù)src。
-
- 配置屬性
屬性方法以“.”鏈?zhǔn)秸{(diào)用的方式配置系統(tǒng)組件的樣式和其他屬性丧鸯,建議每個(gè)屬性方法單獨(dú)寫(xiě)一行躁锡。- 配置Text組件的字體大小。
Text('test') .fontSize(12)
- 配置組件的多個(gè)屬性。
Image('test.jpg') .alt('error.jpg') .width(100) .height(100)
- 除了直接傳遞常量參數(shù)外京髓,還可以傳遞變量或表達(dá)式。
Text('hello') .fontSize(this.size) Image('test.jpg') .width(this.count % 2 === 0 ? 100 : 200) .height(this.offset + 100)
- 對(duì)于系統(tǒng)組件让蕾,ArkUI還為其屬性預(yù)定義了一些枚舉類型供開(kāi)發(fā)者調(diào)用铡俐,枚舉類型可以作為參數(shù)傳遞,但必須滿足參數(shù)類型要求招刹。
例如恬试,可以按以下方式配置Text組件的顏色和字體樣式。Text('hello') .fontSize(20) .fontColor(Color.Red) .fontWeight(FontWeight.Bold)
- 配置Text組件的字體大小。
- 配置事件
事件方法以“.”鏈?zhǔn)秸{(diào)用的方式配置系統(tǒng)組件支持的事件疯暑,建議每個(gè)事件方法單獨(dú)寫(xiě)一行训柴。- 使用lambda表達(dá)式配置組件的事件方法。
Button('Click me') .onClick(() => { this.myText = 'ArkUI'; })
- 使用匿名函數(shù)表達(dá)式配置組件的事件方法妇拯,要求使用bind幻馁,以確保函數(shù)體中的this指向當(dāng)前組件。
Button('add counter') .onClick(function(){ this.counter += 2; }.bind(this))
- 使用組件的成員函數(shù)配置組件的事件方法越锈。
myClickHandler(): void { this.counter += 2; } ... Button('add counter') .onClick(this.myClickHandler.bind(this))
- 使用lambda表達(dá)式配置組件的事件方法。
- 配置子組件
如果組件支持子組件配置仗嗦,則需在尾隨閉包"{...}"中為組件添加子組件的UI描述。Column甘凭、Row稀拐、Stack、Grid对蒲、List等組件都是容器組件钩蚊。
- 以下是簡(jiǎn)單的Column組件配置子組件的示例。
Column() { Text('Hello') .fontSize(100) Divider() Text(this.myText) .fontSize(100) .fontColor(Color.Red) }
- 容器組件均支持子組件配置蹈矮,可以實(shí)現(xiàn)相對(duì)復(fù)雜的多級(jí)嵌套砰逻。
Column() { Row() { Image('test1.jpg') .width(100) .height(100) Button('click +1') .onClick(() => { console.info('+1 clicked!'); }) } }
自定義組件
在ArkUI中,UI顯示的內(nèi)容均為組件泛鸟,由框架直接提供的稱為系統(tǒng)組件蝠咆,由開(kāi)發(fā)者定義的稱為自定義組件。
自定義組件具有以下特點(diǎn):
- 可組合:允許開(kāi)發(fā)者組合使用系統(tǒng)組件、及其屬性和方法刚操。
- 可重用:自定義組件可以被其他組件重用闸翅,并作為不同的實(shí)例在不同的父組件或容器中使用。
- 數(shù)據(jù)驅(qū)動(dòng)UI更新:通過(guò)狀態(tài)變量的改變菊霜,來(lái)驅(qū)動(dòng)UI的刷新坚冀。
自定義組件的基本用法:
@Component
struct HelloComponent {
@State message: string = 'Hello, World!';
build() {
// HelloComponent自定義組件組合系統(tǒng)組件Row和Text
Row() {
Text(this.message)
.onClick(() => {
// 狀態(tài)變量message的改變驅(qū)動(dòng)UI刷新,UI從'Hello, World!'刷新為'Hello, ArkUI!'
this.message = 'Hello, ArkUI!';
})
}
}
}
HelloComponent可以在其他自定義組件中的build()函數(shù)中多次創(chuàng)建鉴逞,實(shí)現(xiàn)自定義組件的重用记某。
@Entry
@Component
struct ParentComponent {
build() {
Column() {
Text('ArkUI message')
HelloComponent({ message: 'Hello, World!' });
Divider()
HelloComponent({ message: '你好!' });
}
}
}
創(chuàng)建自定義組件
- 自定義組建的基本結(jié)構(gòu)
-
struct
:自定義組件基于struct實(shí)現(xiàn),struct + 自定義組件名 + {...}的組合構(gòu)成自定義組件构捡,不能有繼承關(guān)系液南。對(duì)于struct的實(shí)例化,可以省略new勾徽。注:自定義組件名滑凉、類名、函數(shù)名不能和系統(tǒng)組件名相同喘帚。 -
@Component
:@Component裝飾器僅能裝飾struct關(guān)鍵字聲明的數(shù)據(jù)結(jié)構(gòu)畅姊。struct被@Component裝飾后具備組件化的能力,需要實(shí)現(xiàn)build方法描述UI啥辨,一個(gè)struct只能被一個(gè)@Component裝飾涡匀。注: 從API version 9開(kāi)始,該裝飾器支持在ArkTS卡片中使用溉知。@Component struct MyComponent { }
-
-
build()
函數(shù):build()函數(shù)用于定義自定義組件的聲明式UI描述陨瘩,自定義組件必須定義build()函數(shù)。@Component struct MyComponent { build() { } }
- @Entry:@Entry裝飾的自定義組件將作為UI頁(yè)面的入口级乍。在單個(gè)UI頁(yè)面中舌劳,最多可以使用@Entry裝飾一個(gè)自定義組件。@Entry可以接受一個(gè)可選的LocalStorage的參數(shù). 注: 從API version 9開(kāi)始玫荣,該裝飾器支持在ArkTS卡片中使用.
@Entry @Component struct MyComponent { }
- 成員函數(shù)/變量
自定義組件除了必須要實(shí)現(xiàn)build()函數(shù)外甚淡,還可以實(shí)現(xiàn)其他成員函數(shù),成員函數(shù)具有以下約束:- 不支持靜態(tài)函數(shù)捅厂。
- 成員函數(shù)的訪問(wèn)始終是私有的, 變量的訪問(wèn)規(guī)則與成員函數(shù)的訪問(wèn)規(guī)則相同贯卦。
- 自定義組件的成員變量本地初始化有些是可選的,有些是必選的焙贷。具體是否需要本地初始化撵割,是否需要從父組件通過(guò)參數(shù)傳遞初始化子組件的成員變量,請(qǐng)參考狀態(tài)管理辙芍。
- 自定義組件參數(shù)規(guī)定
我們已經(jīng)了解到啡彬,可以在build方法或者@Builder裝飾的函數(shù)里創(chuàng)建自定義組件羹与,在創(chuàng)建的過(guò)程中,參數(shù)可以被提供給組件往踢。@Component struct MyComponent { private countDownFrom: number = 0; private color: Color = Color.Blue; build() { } } @Entry @Component struct ParentComponent { private someColor: Color = Color.Pink; build() { Column() { // 創(chuàng)建MyComponent實(shí)例菲语,并將創(chuàng)建MyComponent成員變量countDownFrom初始化為10妄辩,將成員變量color初始化為this.someColor MyComponent({ countDownFrom: 10, color: this.someColor }) } } }
- build()函數(shù)
所有聲明在build()函數(shù)的語(yǔ)言佩憾,我們統(tǒng)稱為UI描述語(yǔ)言,UI描述語(yǔ)言需要遵循以下規(guī)則:-
@Entry
裝飾的自定義組件,其build()函數(shù)下的根節(jié)點(diǎn)唯一且必要,且必須為容器組件,其中ForEach禁止作為根節(jié)點(diǎn)。@Component
裝飾的自定義組件,其build()函數(shù)下的根節(jié)點(diǎn)唯一且必要,可以為非容器組件创肥,其中ForEach禁止作為根節(jié)點(diǎn)。@Entry @Component struct MyComponent { build() { // 根節(jié)點(diǎn)唯一且必要,必須為容器組件 Row() { ChildComponent() } } } @Component struct ChildComponent { build() { // 根節(jié)點(diǎn)唯一且必要,可為非容器組件 Image('test.jpg') } }
- build()函數(shù)內(nèi)不允許聲明本地變量,反例如下。
build() { // 反例:不允許聲明本地變量 let a: number = 1; }
-
- build()函數(shù)內(nèi)不允許在UI描述里直接使用console.info,但允許在方法或者函數(shù)里使用,反例如下。
build() { // 反例:不允許console.info console.info('print debug log'); }
- build()函數(shù)內(nèi)不允許創(chuàng)建本地的作用域,反例如下。
build() { // 反例:不允許本地作用域 { ... } }
- build()函數(shù)內(nèi)不允許調(diào)用除了被@Builder裝飾以外的方法,允許系統(tǒng)組件的參數(shù)是TS方法的返回值。
@Component struct ParentComponent { doSomeCalculations() { } calcTextValue(): string { return 'Hello World'; } @Builder doSomeRender() { Text(`Hello World`) } build() { Column() { // 反例:不能調(diào)用沒(méi)有用@Builder裝飾的方法 this.doSomeCalculations(); // 正例:可以調(diào)用 this.doSomeRender(); // 正例:參數(shù)可以為調(diào)用TS方法的返回值 Text(this.calcTextValue()) } } }
- build()函數(shù)內(nèi)不允許switch語(yǔ)法,如果需要使用條件判斷,請(qǐng)使用if。反例如下。
build() { Column() { // 反例:不允許使用switch語(yǔ)法 switch (expression) { case 1: Text('...') break; case 2: Image('...') break; default: Text('...') break; } } }
- build()函數(shù)內(nèi)不允許使用表達(dá)式,反例如下。
build() { Column() { // 反例:不允許使用表達(dá)式 (this.aVar > 10) ? Text('...') : Image('...') } }
- 自定義組件通用樣式
自定義組件通過(guò)“.”鏈?zhǔn)秸{(diào)用的形式設(shè)置通用樣式振乏。
注意: ArkUI給自定義組件設(shè)置樣式時(shí)误澳,相當(dāng)于給MyComponent2套了一個(gè)不可見(jiàn)的容器組件裆装,而這些樣式是設(shè)置在容器組件上的昙沦,而非直接設(shè)置給MyComponent2的Button組件懒熙。通過(guò)渲染結(jié)果我們可以很清楚的看到泌豆,背景顏色紅色并沒(méi)有直接生效在Button上,而是生效在Button所處的開(kāi)發(fā)者不可見(jiàn)的容器組件上。@Component struct MyComponent2 { build() { Button(`Hello World`) } } @Entry @Component struct MyComponent { build() { Row() { MyComponent2() .width(200) .height(300) .backgroundColor(Color.Red) } } }
頁(yè)面和自定義組件生命周期
頁(yè)面生命周期,即被@Entry裝飾的組件生命周期垢夹,提供以下生命周期接口:
-
onPageShow
頁(yè)面每次顯示時(shí)觸發(fā)。 頁(yè)面生命周期方法 -
onPageHide
頁(yè)面每次隱藏時(shí)觸發(fā)一次。 頁(yè)面生命周期方法 -
onBackPress
當(dāng)用戶點(diǎn)擊返回按鈕時(shí)觸發(fā)。頁(yè)面生命周期方法
組件生命周期,即一般用@Component裝飾的自定義組件的生命周期,提供以下生命周期接口:
-
aboutToAppear
組件即將出現(xiàn)時(shí)回調(diào)該接口,具體時(shí)機(jī)為在創(chuàng)建自定義組件的新實(shí)例后,在執(zhí)行其build()函數(shù)之前執(zhí)行。 組件生命周期方法 -
aboutToDisappear
在自定義組件即將析構(gòu)銷毀時(shí)執(zhí)行。 組件生命周期方法
[圖片上傳失敗...(image-c82397-1697789591540)]
-
自定義組件的創(chuàng)建和渲染流程
- 自定義組件的創(chuàng)建:自定義組件的實(shí)例由ArkUI框架創(chuàng)建。
- 初始化自定義組件的成員變量:通過(guò)本地默認(rèn)值或者構(gòu)造方法傳遞參數(shù)來(lái)初始化自定義組件的成員變量柠新,
初始化順序?yàn)槌蓡T變量的定義順序
。 - 如果開(kāi)發(fā)者定義了aboutToAppear痢甘,則執(zhí)行aboutToAppear方法放椰。
- 在首次渲染的時(shí)候,執(zhí)行build方法渲染系統(tǒng)組件影暴,如果子組件為自定義組件妆兑,則創(chuàng)建自定義組件的實(shí)例潭千。在執(zhí)行build()函數(shù)的過(guò)程中,框架會(huì)觀察每個(gè)狀態(tài)變量的讀取狀態(tài)蝶桶,將保存兩個(gè)map:
- 狀態(tài)變量 -> UI組件(包括ForEach和if)。
- UI組件 -> 此組件的更新函數(shù),即一個(gè)lambda方法透硝,作為build()函數(shù)的子集,創(chuàng)建對(duì)應(yīng)的UI組件并執(zhí)行其屬性方法,示意如下。
當(dāng)應(yīng)用在后臺(tái)啟動(dòng)時(shí)喊巍,此時(shí)應(yīng)用進(jìn)程并沒(méi)有銷毀,所以僅需要執(zhí)行onPageShow海洼。build() { ... this.observeComponentCreation(() => { Button.create(); }) this.observeComponentCreation(() => { Text.create(); }) ... }
-
自定義組件重新渲染
當(dāng)事件句柄被觸發(fā)(比如設(shè)置了點(diǎn)擊事件是整,即觸發(fā)點(diǎn)擊事件)改變了狀態(tài)變量時(shí),或者LocalStorage / AppStorage中的屬性更改球化,并導(dǎo)致綁定的狀態(tài)變量更改其值時(shí):- 框架觀察到了變化句伶,將啟動(dòng)重新渲染。
- 根據(jù)框架持有的兩個(gè)map(自定義組件的創(chuàng)建和渲染流程中第4步)身冬,框架可以知道該狀態(tài)變量管理了哪些UI組件嘿歌,以及這些UI組件對(duì)應(yīng)的更新函數(shù)。執(zhí)行這些UI組件的更新函數(shù)沪编,實(shí)現(xiàn)最小化更新相嵌。
-
自定義組件的刪除
如果if組件的分支改變饭宾,或者ForEach循環(huán)渲染中數(shù)組的個(gè)數(shù)改變批糟,組件將被刪除:- 在刪除組件之前,將調(diào)用其aboutToDisappear生命周期函數(shù)看铆,標(biāo)記著該節(jié)點(diǎn)將要被銷毀。ArkUI的節(jié)點(diǎn)刪除機(jī)制是:后端節(jié)點(diǎn)直接從組件樹(shù)上摘下,后端節(jié)點(diǎn)被銷毀否淤,對(duì)前端節(jié)點(diǎn)解引用悄但,當(dāng)前端節(jié)點(diǎn)已經(jīng)沒(méi)有引用時(shí),將被JS虛擬機(jī)垃圾回收石抡。
- 自定義組件和它的變量將被刪除檐嚣,如果其有同步的變量,比如@Link汁雷、@Prop净嘀、@StorageLink,將從同步源上取消注冊(cè)侠讯。
不建議在生命周期aboutToDisappear內(nèi)使用async await挖藏,如果在生命周期的aboutToDisappear使用異步操作(Promise或者回調(diào)方法),自定義組件將被保留在Promise的閉包中厢漩,直到回調(diào)方法被執(zhí)行完膜眠,這個(gè)行為阻止了自定義組件的垃圾回收。
以下示例展示了生命周期的調(diào)用時(shí)機(jī):
// Index.ets import router from '@ohos.router'; @Entry @Component struct MyComponent { @State showChild: boolean = true; // 只有被@Entry裝飾的組件才可以調(diào)用頁(yè)面的生命周期 onPageShow() { console.info('Index onPageShow'); } // 只有被@Entry裝飾的組件才可以調(diào)用頁(yè)面的生命周期 onPageHide() { console.info('Index onPageHide'); } // 只有被@Entry裝飾的組件才可以調(diào)用頁(yè)面的生命周期 onBackPress() { console.info('Index onBackPress'); } // 組件生命周期 aboutToAppear() { console.info('MyComponent aboutToAppear'); } // 組件生命周期 aboutToDisappear() { console.info('MyComponent aboutToDisappear'); } build() { Column() { // this.showChild為true溜嗜,創(chuàng)建Child子組件宵膨,執(zhí)行Child aboutToAppear if (this.showChild) { Child() } // this.showChild為false,刪除Child子組件炸宵,執(zhí)行Child aboutToDisappear Button('create or delete Child').onClick(() => { this.showChild = false; }) // push到Page2頁(yè)面辟躏,執(zhí)行onPageHide Button('push to next page') .onClick(() => { router.pushUrl({ url: 'pages/Page2' }); }) } } } @Component struct Child { @State title: string = 'Hello World'; // 組件生命周期 aboutToDisappear() { console.info('[lifeCycle] Child aboutToDisappear') } // 組件生命周期 aboutToAppear() { console.info('[lifeCycle] Child aboutToAppear') } build() { Text(this.title).fontSize(50).onClick(() => { this.title = 'Hello ArkUI'; }) } }
以上示例中,Index頁(yè)面包含兩個(gè)自定義組件土全,一個(gè)是被@Entry裝飾的MyComponent捎琐,也是頁(yè)面的入口組件,即頁(yè)面的根節(jié)點(diǎn)裹匙;一個(gè)是Child瑞凑,是MyComponent的子組件。只有@Entry裝飾的節(jié)點(diǎn)才可以生效頁(yè)面的生命周期方法概页,所以MyComponent中聲明了當(dāng)前Index頁(yè)面的頁(yè)面生命周期函數(shù)籽御。MyComponent和其子組件Child也同時(shí)也聲明了組件的生命周期函數(shù)。
- 應(yīng)用冷啟動(dòng)的初始化流程為:MyComponent aboutToAppear --> MyComponent build --> Child aboutToAppear --> Child build --> Child build執(zhí)行完畢 --> MyComponent build執(zhí)行完畢 --> Index onPageShow惰匙。
- 點(diǎn)擊“delete Child”技掏,if綁定的this.showChild變成false,刪除Child組件项鬼,會(huì)執(zhí)行Child aboutToDisappear方法零截。
- 點(diǎn)擊“push to next page”,調(diào)用router.pushUrl接口秃臣,跳轉(zhuǎn)到另外一個(gè)頁(yè)面,當(dāng)前Index頁(yè)面隱藏,執(zhí)行頁(yè)面生命周期Index onPageHide奥此。此處調(diào)用的是router.pushUrl接口弧哎,Index頁(yè)面被隱藏,并沒(méi)有銷毀稚虎,所以只調(diào)用onPageHide撤嫩。跳轉(zhuǎn)到新頁(yè)面后,執(zhí)行初始化新頁(yè)面的生命周期的流程蠢终。
- 如果調(diào)用的是router.replaceUrl序攘,則當(dāng)前Index頁(yè)面被銷毀,執(zhí)行的生命周期流程將變?yōu)椋篒ndex onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear寻拂。上文已經(jīng)提到,組件的銷毀是從組件樹(shù)上直接摘下子樹(shù),所以先調(diào)用父組件的aboutToDisappear衙四,再調(diào)用子組件的aboutToDisappear它改,然后執(zhí)行初始化新頁(yè)面的生命周期流程。
- 點(diǎn)擊返回按鈕慌核,觸發(fā)頁(yè)面生命周期Index onBackPress距境,且觸發(fā)返回一個(gè)頁(yè)面后會(huì)導(dǎo)致當(dāng)前Index頁(yè)面被銷毀。
- 最小化應(yīng)用或者應(yīng)用進(jìn)入后臺(tái)垮卓,觸發(fā)Index onPageHide垫桂。當(dāng)前Index頁(yè)面沒(méi)有被銷毀,所以并不會(huì)執(zhí)行組件的aboutToDisappear粟按。應(yīng)用回到前臺(tái)诬滩,執(zhí)行Index onPageShow。
- 退出應(yīng)用钾怔,執(zhí)行Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear碱呼。
@Builder裝飾器
使用說(shuō)明:
- 自定義組件內(nèi)自定義構(gòu)建函數(shù)
- 全局自定義構(gòu)建函數(shù)
- 全局的自定義構(gòu)建函數(shù)可以被整個(gè)應(yīng)用獲取,不允許使用this和bind方法宗侦。
- 如果不涉及組件狀態(tài)變化愚臀,建議使用全局的自定義構(gòu)建方法。
參數(shù)傳遞規(guī)則:
- 按值傳遞
- 調(diào)用@Builder裝飾的函數(shù)默認(rèn)按值傳遞矾利。當(dāng)傳遞的參數(shù)為狀態(tài)變量時(shí)姑裂,狀態(tài)變量的改變不會(huì)引起@Builder方法內(nèi)的UI刷新。所以當(dāng)使用狀態(tài)變量的時(shí)候男旗,推薦使用按引用傳遞舶斧。
@Builder function ABuilder(paramA1: string) { Row() { Text(`UseStateVarByValue: ${paramA1} `) } } @Entry @Component struct Parent { label: string = 'Hello'; build() { Column() { ABuilder(this.label) } } }
- 調(diào)用@Builder裝飾的函數(shù)默認(rèn)按值傳遞矾利。當(dāng)傳遞的參數(shù)為狀態(tài)變量時(shí)姑裂,狀態(tài)變量的改變不會(huì)引起@Builder方法內(nèi)的UI刷新。所以當(dāng)使用狀態(tài)變量的時(shí)候男旗,推薦使用按引用傳遞舶斧。
- 按引用傳遞
- 按引用傳遞參數(shù)時(shí),傳遞的參數(shù)可為狀態(tài)變量察皇,且狀態(tài)變量的改變會(huì)引起@Builder方法內(nèi)的UI刷新茴厉。ArkUI提供
$$
作為按引用傳遞參數(shù)的范式泽台。//全局構(gòu)建 @Builder function ABuilder($$: { paramA1: string }) { Row() { Text(`UseStateVarByReference: ${$$.paramA1} `) } } //組件內(nèi)構(gòu)建 @Builder ABuilder( $$ : { paramA1: string } ); @Entry @Component struct Parent { @State label: string = 'Hello'; build() { Column() { // 在Parent組件中調(diào)用ABuilder的時(shí)候,將this.label引用傳遞給ABuilder ABuilder({ paramA1: this.label }) Button('Click me').onClick(() => { // 點(diǎn)擊“Click me”后矾缓,UI從“Hello”刷新為“ArkUI” this.label = 'ArkUI'; }) } } }
- 按引用傳遞參數(shù)時(shí),傳遞的參數(shù)可為狀態(tài)變量察皇,且狀態(tài)變量的改變會(huì)引起@Builder方法內(nèi)的UI刷新茴厉。ArkUI提供
@BuilderParam裝飾器:引用@Builder函數(shù)
使用場(chǎng)景:
- 參數(shù)初始化組件
- 尾隨閉包初始化組件: 開(kāi)發(fā)者可以將尾隨閉包內(nèi)的內(nèi)容看做@Builder裝飾的函數(shù)傳給@BuilderParam怀酷。示例如下:
// xxx.ets @Component struct CustomContainer { @Prop header: string; @BuilderParam closer: () => void build() { Column() { Text(this.header) .fontSize(30) this.closer() } } } @Builder function specificParam(label1: string, label2: string) { Column() { Text(label1) .fontSize(30) Text(label2) .fontSize(30) } } @Entry @Component struct CustomContainerUser { @State text: string = 'header'; build() { Column() { // 創(chuàng)建CustomContainer,在創(chuàng)建CustomContainer時(shí)嗜闻,通過(guò)其后緊跟一個(gè)大括號(hào)“{}”形成尾隨閉包 // 作為傳遞給子組件CustomContainer @BuilderParam closer: () => void的參數(shù) CustomContainer({ header: this.text }) { Column() { specificParam('testA', 'testB') }.backgroundColor(Color.Yellow) .onClick(() => { this.text = 'changeHeader'; }) } } } }
@Styles裝飾器:定義組件重用樣式
@Styles
裝飾器可以將多條樣式設(shè)置提煉成一個(gè)方法蜕依,直接在組件聲明的位置調(diào)用。通過(guò)@Styles裝飾器可以快速定義并復(fù)用自定義樣式琉雳。用于快速定義并復(fù)用自定義樣式样眠。可以類比為通用的css樣式
使用說(shuō)明:
- 當(dāng)前@Styles僅支持通用屬性和通用事件翠肘。
- @Styles方法不支持參數(shù)
- @Styles可以定義在組件內(nèi)或全局檐束,在全局定義時(shí)需在方法名前面添加function關(guān)鍵字,組件內(nèi)定義時(shí)則不需要添加function關(guān)鍵字锯茄。
- 定義在組件內(nèi)的@Styles可以通過(guò)this訪問(wèn)組件的常量和狀態(tài)變量厢塘,并可以在@Styles里通過(guò)事件來(lái)改變狀態(tài)變量的值
- 組件內(nèi)@Styles的優(yōu)先級(jí)高于全局@Styles。
框架優(yōu)先找當(dāng)前組件內(nèi)的@Styles肌幽,如果找不到晚碾,則會(huì)全局查找。
// 定義在全局的@Styles封裝的樣式
@Styles function globalFancy () {
.width(150)
.height(100)
.backgroundColor(Color.Pink)
}
@Entry
@Component
struct FancyUse {
@State heightValue: number = 100
// 定義在組件內(nèi)的@Styles封裝的樣式
@Styles fancy() {
.width(200)
.height(this.heightValue)
.backgroundColor(Color.Yellow)
.onClick(() => {
this.heightValue = 200
})
}
build() {
Column({ space: 10 }) {
// 使用全局的@Styles封裝的樣式
Text('FancyA')
.globalFancy ()
.fontSize(30)
// 使用組件內(nèi)的@Styles封裝的樣式
Text('FancyB')
.fancy()
.fontSize(30)
}
}
}
@Extend裝飾器:定義擴(kuò)展組件樣式
使用說(shuō)明:
@Extend(UIComponentName) function functionName { ... }
使用規(guī)則:
- 和@Styles不同喂急,@Extend僅支持定義在全局格嘁,不支持在組件內(nèi)部定義。
- 和@Styles不同廊移,@Extend支持封裝指定的組件的私有屬性和私有事件和預(yù)定義相同組件的@Extend的方法糕簿。
// @Extend(Text)可以支持Text的私有屬性fontColor @Extend(Text) function fancy () { .fontColor(Color.Red) } // superFancyText可以調(diào)用預(yù)定義的fancy @Extend(Text) function superFancyText(size:number) { .fontSize(size) .fancy() }
- 和@Styles不同,@Extend裝飾的方法支持參數(shù)狡孔,開(kāi)發(fā)者可以在調(diào)用時(shí)傳遞參數(shù)懂诗,調(diào)用遵循TS方法傳值調(diào)用。
// xxx.ets @Extend(Text) function fancy (fontSize: number) { .fontColor(Color.Red) .fontSize(fontSize) } @Entry @Component struct FancyUse { build() { Row({ space: 10 }) { Text('Fancy') .fancy(16) Text('Fancy') .fancy(24) } } }
- @Extend裝飾的方法的參數(shù)可以為function苗膝,作為Event事件的句柄殃恒。
@Extend(Text) function makeMeClick(onClick: () => void) { .backgroundColor(Color.Blue) .onClick(onClick) } @Entry @Component struct FancyUse { @State label: string = 'Hello World'; onClickHandler() { this.label = 'Hello ArkUI'; } build() { Row({ space: 10 }) { Text(`${this.label}`) .makeMeClick(this.onClickHandler.bind(this)) } } }
- @Extend的參數(shù)可以為狀態(tài)變量,當(dāng)狀態(tài)變量改變時(shí)辱揭,UI可以正常的被刷新渲染离唐。
@Extend(Text) function fancy (fontSize: number) { .fontColor(Color.Red) .fontSize(fontSize) } @Entry @Component struct FancyUse { @State fontSizeValue: number = 20 build() { Row({ space: 10 }) { Text('Fancy') .fancy(this.fontSizeValue) .onClick(() => { this.fontSizeValue = 30 }) } } }
stateStyles:多態(tài)樣式
@Styles和@Extend僅僅應(yīng)用于靜態(tài)頁(yè)面的樣式復(fù)用,stateStyles可以依據(jù)組件的內(nèi)部狀態(tài)的不同问窃,快速設(shè)置不同樣式亥鬓。這就是我們本章要介紹的內(nèi)容stateStyles(又稱為:多態(tài)樣式)。
stateStyles是屬性方法域庇,可以根據(jù)UI內(nèi)部狀態(tài)來(lái)設(shè)置樣式嵌戈,類似于css偽類覆积,但語(yǔ)法不同。ArkUI提供以下四種狀態(tài):
- focused:獲焦態(tài)
- normal:正常態(tài)咕别。
- pressed:按壓態(tài)技健。
- disabled:不可用態(tài)。
- @Styles和stateStyles聯(lián)合使用
正常態(tài)和按壓態(tài)切換@Entry @Component struct MyComponent { @Styles normalStyle() { .backgroundColor(Color.Gray) } @Styles pressedStyle() { .backgroundColor(Color.Red) } build() { Column() { Text('Text1') .fontSize(50) .fontColor(Color.White) .stateStyles({ normal: this.normalStyle, pressed: this.pressedStyle, }) } } }
- 在stateStyles里使用常規(guī)變量和狀態(tài)變量
Button默認(rèn)獲焦顯示紅色惰拱,點(diǎn)擊事件觸發(fā)后,獲焦態(tài)變?yōu)榉凵?@Entry @Component struct CompWithInlineStateStyles { @State focusedColor: Color = Color.Red; normalColor: Color = Color.Green build() { Button('clickMe').height(100).width(100) .stateStyles({ normal: { .backgroundColor(this.normalColor) }, focused: { .backgroundColor(this.focusedColor) } }) .onClick(() => { this.focusedColor = Color.Pink }) .margin('30%') } }
ArkTs狀態(tài)管理
-
@State
:@State裝飾的變量擁有其所屬組件的狀態(tài)啊送,可以作為其子組件單向和雙向同步的數(shù)據(jù)源偿短。當(dāng)其數(shù)值改變時(shí),會(huì)引起相關(guān)組件的渲染刷新馋没。 -
@Prop
:@Prop裝飾的變量可以和父組件建立單向同步關(guān)系昔逗,@Prop裝飾的變量是可變的,但修改不會(huì)同步回父組件篷朵。 -
@Link
:@Link裝飾的變量和父組件構(gòu)建雙向同步關(guān)系的狀態(tài)變量勾怒,父組件會(huì)接受來(lái)自@Link裝飾的變量的修改的同步,父組件的更新也會(huì)同步給@Link裝飾的變量声旺。 -
@Provide/@Consume
:@Provide/@Consume裝飾的變量用于跨組件層級(jí)(多層組件)同步狀態(tài)變量笔链,可以不需要通過(guò)參數(shù)命名機(jī)制傳遞,通過(guò)alias(別名)或者屬性名綁定腮猖。 -
@Observed
:@Observed裝飾class鉴扫,需要觀察多層嵌套場(chǎng)景的class需要被@Observed裝飾。單獨(dú)使用@Observed沒(méi)有任何作用澈缺,需要和@ObjectLink坪创、@Prop連用。 -
@ObjectLink
:@ObjectLink裝飾的變量接收@Observed裝飾的class的實(shí)例姐赡,應(yīng)用于觀察多層嵌套場(chǎng)景莱预,和父組件的數(shù)據(jù)源構(gòu)建雙向同步。
管理應(yīng)用擁有的狀態(tài)概述:
裝飾器僅能在頁(yè)面內(nèi)项滑,即一個(gè)組件樹(shù)上共享狀態(tài)變量依沮。如果開(kāi)發(fā)者要實(shí)現(xiàn)應(yīng)用級(jí)的,或者多個(gè)頁(yè)面的狀態(tài)數(shù)據(jù)共享杖们,就需要用到應(yīng)用級(jí)別的狀態(tài)管理的概念悉抵。ArkTS根據(jù)不同特性,提供了多種應(yīng)用狀態(tài)管理的能力:
-
LocalStorage
:頁(yè)面級(jí)UI狀態(tài)存儲(chǔ)摘完,通常用于UIAbility內(nèi)姥饰、頁(yè)面間的狀態(tài)共享。 -
AppStorage
:特殊的單例LocalStorage對(duì)象孝治,由UI框架在應(yīng)用程序啟動(dòng)時(shí)創(chuàng)建列粪,為應(yīng)用程序UI狀態(tài)屬性提供中央存儲(chǔ)审磁; -
PersistentStorage
:持久化存儲(chǔ)UI狀態(tài),通常和AppStorage配合使用岂座,選擇AppStorage存儲(chǔ)的數(shù)據(jù)寫(xiě)入磁盤(pán)态蒂,以確保這些屬性在應(yīng)用程序重新啟動(dòng)時(shí)的值與應(yīng)用程序關(guān)閉時(shí)的值相同;LocalStorage和AppStorage都是運(yùn)行時(shí)的內(nèi)存费什,但是在應(yīng)用退出再次啟動(dòng)后钾恢,依然能保存選定的結(jié)果,是應(yīng)用開(kāi)發(fā)中十分常見(jiàn)的現(xiàn)象鸳址,這就需要用到PersistentStorage瘩蚪。
注意: PersistentStorage的持久化變量最好是小于2kb的數(shù)據(jù),不要大量的數(shù)據(jù)持久化稿黍,因?yàn)镻ersistentStorage寫(xiě)入磁盤(pán)的操作是同步的疹瘦,大量的數(shù)據(jù)本地化讀寫(xiě)會(huì)同步在UI線程中執(zhí)行,影響UI渲染性能巡球。如果開(kāi)發(fā)者需要存儲(chǔ)大量的數(shù)據(jù)言沐,建議使用數(shù)據(jù)庫(kù)api。PersistentStorage只能在UI頁(yè)面內(nèi)使用酣栈,否則將無(wú)法持久化數(shù)據(jù)险胰。 -
Environment
:應(yīng)用程序運(yùn)行的設(shè)備的環(huán)境參數(shù),環(huán)境參數(shù)會(huì)同步到AppStorage中钉嘹,可以和AppStorage搭配使用鸯乃。
ArkTs渲染控制
ArkUI通過(guò)自定義組件的build()函數(shù)和@builder裝飾器中的聲明式UI描述語(yǔ)句構(gòu)建相應(yīng)的UI。在聲明式描述語(yǔ)句中開(kāi)發(fā)者除了使用系統(tǒng)組件外跋涣,還可以使用渲染控制語(yǔ)句來(lái)輔助UI的構(gòu)建缨睡,這些渲染控制語(yǔ)句包括控制組件是否顯示的條件渲染語(yǔ)句,基于數(shù)組數(shù)據(jù)快速生成組件的循環(huán)渲染語(yǔ)句以及針對(duì)大數(shù)據(jù)量場(chǎng)景的數(shù)據(jù)懶加載語(yǔ)句陈辱。
-
if/else:條件渲染
更新機(jī)制:
當(dāng)if奖年、else if后跟隨的狀態(tài)判斷中使用的狀態(tài)變量值變化時(shí),條件渲染語(yǔ)句會(huì)進(jìn)行更新沛贪,更新步驟如下:- 評(píng)估if和else if的狀態(tài)判斷條件陋守,如果分支沒(méi)有變化,請(qǐng)無(wú)需執(zhí)行以下步驟利赋。如果分支有變化水评,則執(zhí)行2、3步驟:
- 刪除此前構(gòu)建的所有子組件媚送。
- 執(zhí)行新分支的構(gòu)造函數(shù)中燥,將獲取到的組件添加到if父容器中。如果缺少適用的else分支塘偎,則不構(gòu)建任何內(nèi)容疗涉。
條件可以包括Typescript表達(dá)式拿霉。對(duì)于構(gòu)造函數(shù)中的表達(dá)式,此類表達(dá)式不得更改應(yīng)用程序狀態(tài)咱扣。
@Component struct CounterView { @State counter: number = 0; label: string = 'unknown'; build() { Row() { Text(`${this.label}`) Button(`counter ${this.counter} +1`) .onClick(() => { this.counter += 1; }) } } } @Entry @Component struct MainView { @State toggle: boolean = true; build() { Column() { if (this.toggle) { CounterView({ label: 'CounterView #positive' }) } else { CounterView({ label: 'CounterView #negative' }) } Button(`toggle ${this.toggle}`) .onClick(() => { this.toggle = !this.toggle; }) } } }
-
ForEach:循環(huán)渲染
ForEach基于數(shù)組類型數(shù)據(jù)執(zhí)行循環(huán)渲染绽淘。- forEach接口描述
ForEach( arr: any[], itemGenerator: (item: any, index?: number) => void, keyGenerator?: (item: any, index?: number) => string )
- 使用限制:
- ForEach必須在容器組件內(nèi)使用。
- 生成的子組件應(yīng)當(dāng)是允許包含在ForEach父容器組件中的子組件闹伪。
- 允許子組件生成器函數(shù)中包含if/else條件渲染沪铭,同時(shí)也允許ForEach包含在if/else條件渲染語(yǔ)句中。
- itemGenerator函數(shù)的調(diào)用順序不一定和數(shù)組中的數(shù)據(jù)項(xiàng)相同偏瓤,在開(kāi)發(fā)過(guò)程中不要假設(shè)itemGenerator和keyGenerator函數(shù)是否執(zhí)行及其執(zhí)行順序伦意。例如,以下示例可能無(wú)法正確運(yùn)行:
ForEach(anArray.map((item1, index1) => { return { i: index1 + 1, data: item1 }; }), item => Text(`${item.i}. item.data.label`), item => item.data.id.toString())
- forEach接口描述
-
LazyForEach:數(shù)據(jù)懶加載
LazyForEach從提供的數(shù)據(jù)源中按需迭代數(shù)據(jù)硼补,并在每次迭代過(guò)程中創(chuàng)建相應(yīng)的組件。當(dāng)LazyForEach在滾動(dòng)容器中使用了熏矿,框架會(huì)根據(jù)滾動(dòng)容器可視區(qū)域按需創(chuàng)建組件已骇,當(dāng)組件滑出可視區(qū)域外時(shí),框架會(huì)進(jìn)行組件銷毀回收以降低內(nèi)存占用票编。- 接口描述
LazyForEach( dataSource: IDataSource, // 需要進(jìn)行數(shù)據(jù)迭代的數(shù)據(jù)源 itemGenerator: (item: any) => void, // 子組件生成函數(shù) keyGenerator?: (item: any) => string // (可選) .鍵值生成函數(shù) ): void
- 使用限制
- LazyForEach必須在容器組件內(nèi)使用褪储,僅有List、Grid以及Swiper組件支持?jǐn)?shù)據(jù)懶加載(可配置cachedCount屬性慧域,即只加載可視部分以及其前后少量數(shù)據(jù)用于緩沖)鲤竹,其他組件仍然是一次性加載所有的數(shù)據(jù)。
- LazyForEach在每次迭代中昔榴,必須創(chuàng)建且只允許創(chuàng)建一個(gè)子組件辛藻。
- 生成的子組件必須是允許包含在LazyForEach父容器組件中的子組件。
- 允許LazyForEach包含在if/else條件渲染語(yǔ)句中互订,也允許LazyForEach中出現(xiàn)if/else條件渲染語(yǔ)句吱肌。
- 鍵值生成器必須針對(duì)每個(gè)數(shù)據(jù)生成唯一的值,如果鍵值相同仰禽,將導(dǎo)致鍵值相同的UI組件被框架忽略氮墨,從而無(wú)法在父容器內(nèi)顯示。
- LazyForEach必須使用DataChangeListener對(duì)象來(lái)進(jìn)行更新吐葵,第一個(gè)參數(shù)dataSource使用狀態(tài)變量時(shí)规揪,狀態(tài)變量改變不會(huì)觸發(fā)LazyForEach的UI刷新。
- 為了高性能渲染温峭,通過(guò)DataChangeListener對(duì)象的onDataChange方法來(lái)更新UI時(shí)猛铅,需要生成不同于原來(lái)的鍵值來(lái)觸發(fā)組件刷新。
- itemGenerator函數(shù)的調(diào)用順序不一定和數(shù)據(jù)源中的數(shù)據(jù)項(xiàng)相同诚镰,在開(kāi)發(fā)過(guò)程中不要假設(shè)itemGenerator和keyGenerator函數(shù)是否執(zhí)行及其執(zhí)行順序奕坟。例如祥款,以下示例可能無(wú)法正常運(yùn)行:
LazyForEach(dataSource, item => Text(`${item.i}. item.data.label`), item => item.data.id.toString())
- 示例
// Basic implementation of IDataSource to handle data listener class BasicDataSource implements IDataSource { private listeners: DataChangeListener[] = []; public totalCount(): number { return 0; } public getData(index: number): any { return undefined; } registerDataChangeListener(listener: DataChangeListener): void { if (this.listeners.indexOf(listener) < 0) { console.info('add listener'); this.listeners.push(listener); } } unregisterDataChangeListener(listener: DataChangeListener): void { const pos = this.listeners.indexOf(listener); if (pos >= 0) { console.info('remove listener'); this.listeners.splice(pos, 1); } } notifyDataReload(): void { this.listeners.forEach(listener => { listener.onDataReloaded(); }) } notifyDataAdd(index: number): void { this.listeners.forEach(listener => { listener.onDataAdd(index); }) } notifyDataChange(index: number): void { this.listeners.forEach(listener => { listener.onDataChange(index); }) } notifyDataDelete(index: number): void { this.listeners.forEach(listener => { listener.onDataDelete(index); }) } notifyDataMove(from: number, to: number): void { this.listeners.forEach(listener => { listener.onDataMove(from, to); }) } } class MyDataSource extends BasicDataSource { private dataArray: string[] = []; public totalCount(): number { return this.dataArray.length; } public getData(index: number): any { return this.dataArray[index]; } public addData(index: number, data: string): void { this.dataArray.splice(index, 0, data); this.notifyDataAdd(index); } public pushData(data: string): void { this.dataArray.push(data); this.notifyDataAdd(this.dataArray.length - 1); } } @Entry @Component struct MyComponent { aboutToAppear() { for (var i = 100; i >= 80; i--) { this.data.pushData(`Hello ${i}`) } } private data: MyDataSource = new MyDataSource(); build() { List({ space: 3 }) { LazyForEach(this.data, (item: string) => { ListItem() { Row() { Text(item).fontSize(50) .onAppear(() => { console.info("appear:" + item) }) }.margin({ left: 10, right: 10 }) } .onClick(() => { this.data.pushData(`Hello ${this.data.totalCount()}`); }) }, item => item) }.cachedCount(5) } }
- 接口描述
stage模型應(yīng)用
Stage模型開(kāi)發(fā)概述
[圖片上傳失敗...(image-ed30bb-1697789591540)]
-
UIAbility
組件和ExtensionAbility
組件
Stage模型提供UIAbility和ExtensionAbility兩種類型的組件,這兩種組件都有具體的類承載月杉,支持面向?qū)ο蟮拈_(kāi)發(fā)方式刃跛。- UIAbility組件是一種包含UI界面的應(yīng)用組件,主要用于和用戶交互苛萎。
- ExtensionAbility組件是一種面向特定場(chǎng)景的應(yīng)用組件桨昙。
WindowStage
每個(gè)UIAbility類實(shí)例都會(huì)與一個(gè)WindowStage類實(shí)例綁定,該類提供了應(yīng)用進(jìn)程內(nèi)窗口管理器的作用腌歉。它包含一個(gè)主窗口蛙酪。也就是說(shuō)UIAbility通過(guò)WindowStage持有了一個(gè)窗口,該窗口為ArkUI提供了繪制區(qū)域翘盖。Context
在Stage模型上桂塞,Context及其派生類向開(kāi)發(fā)者提供在運(yùn)行期可以調(diào)用的各種能力。UIAbility組件和各種ExtensionAbility派生類都有各自不同的Context類馍驯,他們都繼承自基類Context阁危,但是各自又根據(jù)所屬組件,提供不同的能力汰瘫。AbilityStage
每個(gè)Entry類型或者Feature類型的HAP在運(yùn)行期都有一個(gè)AbilityStage類實(shí)例狂打,當(dāng)HAP中的代碼首次被加載到進(jìn)程中的時(shí)候,系統(tǒng)會(huì)先創(chuàng)建AbilityStage實(shí)例混弥。每個(gè)在該HAP中定義的UIAbility類趴乡,在實(shí)例化后都會(huì)與該實(shí)例產(chǎn)生關(guān)聯(lián)。開(kāi)發(fā)者可以使用AbilityStage獲取該HAP中UIAbility實(shí)例的運(yùn)行時(shí)信息蝗拿。
Stage模型應(yīng)用/組件級(jí)配置
- 應(yīng)用包名配置
應(yīng)用需要在工程的AppScope目錄下的app.json5
配置文件中配置bundleName標(biāo)簽晾捏,該標(biāo)簽用于標(biāo)識(shí)應(yīng)用的唯一性丁逝。推薦采用反域名形式命名(如com.example.demo官份,建議第一級(jí)為域名后綴com逛薇,第二級(jí)為廠商/個(gè)人名引润,第三級(jí)為應(yīng)用名酒甸,也可以多級(jí))兼贸。 - 應(yīng)用圖標(biāo)和標(biāo)簽配置
Stage模型的應(yīng)用需要配置應(yīng)用圖標(biāo)和應(yīng)用標(biāo)簽忍宋。應(yīng)用圖標(biāo)和標(biāo)簽是在設(shè)置應(yīng)用中使用咧党,例如設(shè)置應(yīng)用中的應(yīng)用列表俗或,會(huì)顯示出對(duì)應(yīng)的圖標(biāo)和標(biāo)簽市怎。
應(yīng)用圖標(biāo)
需要在工程的AppScope目錄下的app.json5
配置文件中配置icon標(biāo)簽。應(yīng)用圖標(biāo)需配置為圖片的資源索引辛慰,配置完成后区匠,該圖片即為應(yīng)用的圖標(biāo)。
應(yīng)用標(biāo)簽
需要在工程的AppScope模塊下的app.json5配置文件中配置label標(biāo)簽。標(biāo)識(shí)應(yīng)用對(duì)用戶顯示的名稱驰弄,需要配置為字符串資源的索引麻汰。 - 入口圖標(biāo)和標(biāo)簽配置
Stage模型支持對(duì)組件配置入口圖標(biāo)和入口標(biāo)簽。入口圖標(biāo)和入口標(biāo)簽會(huì)顯示在桌面上戚篙。
入口圖標(biāo)需要在module.json5
配置文件中配置五鲫,在abilities標(biāo)簽下面有icon
標(biāo)簽。例如希望在桌面上顯示該UIAbility的圖標(biāo)岔擂,則需要在skills標(biāo)簽下面的entities
中添加"entity.system.home"位喂、actions中添加"action.system.home"。同一個(gè)應(yīng)用有多個(gè)UIAbility配置上述字段時(shí)乱灵,桌面上會(huì)顯示出多個(gè)圖標(biāo)塑崖,分別對(duì)應(yīng)各自的UIAbility。
UIAbility組件概述
UIAbility概述:
UIAbility組件是一種包含UI界面的應(yīng)用組件痛倚,主要用于和用戶交互规婆。
UIAbility組件是系統(tǒng)調(diào)度的基本單元,為應(yīng)用提供繪制界面的窗口蝉稳;一個(gè)UIAbility組件中可以通過(guò)多個(gè)頁(yè)面來(lái)實(shí)現(xiàn)一個(gè)功能模塊聋呢。每一個(gè)UIAbility組件實(shí)例,都對(duì)應(yīng)于一個(gè)最近任務(wù)列表中的任務(wù)颠区。-
UIAbility組件生命周期
- UIAbility的生命周期包括Create、Foreground通铲、Background毕莱、Destroy四個(gè)狀態(tài)
-
UIAbility組件啟動(dòng)模式
- singleton(單實(shí)例模式)
每次調(diào)用startAbility()方法時(shí),如果應(yīng)用進(jìn)程中該類型的UIAbility實(shí)例已經(jīng)存在颅夺,則復(fù)用系統(tǒng)中的UIAbility實(shí)例朋截。系統(tǒng)中只存在唯一一個(gè)該UIAbility實(shí)例,即在最近任務(wù)列表中只存在一個(gè)該類型的UIAbility實(shí)例吧黄。如果需要使用singleton啟動(dòng)模式部服,在module.json5配置文件中的"launchType"字段配置為"singleton"即可。 { "module": { // ... "abilities": [ { "launchType": "singleton", // ... } ] } }
- standard(標(biāo)準(zhǔn)實(shí)例模式)
standard啟動(dòng)模式為標(biāo)準(zhǔn)實(shí)例模式拗慨,每次調(diào)用startAbility()方法時(shí)廓八,都會(huì)在應(yīng)用進(jìn)程中創(chuàng)建一個(gè)新的該類型UIAbility實(shí)例。即在最近任務(wù)列表中可以看到有多個(gè)該類型的UIAbility實(shí)例赵抢。這種情況下可以將UIAbility配置為standard(標(biāo)準(zhǔn)實(shí)例模式)剧蹂。standard啟動(dòng)模式的開(kāi)發(fā)使用,在module.json5配置文件中的"launchType"字段配置為"standard"即可烦却。 { "module": { // ... "abilities": [ { "launchType": "standard", // ... } ] } }
- specified(指定實(shí)例模式)
specified啟動(dòng)模式為指定實(shí)例模式宠叼,針對(duì)一些特殊場(chǎng)景使用(例如文檔應(yīng)用中每次新建文檔希望都能新建一個(gè)文檔實(shí)例,重復(fù)打開(kāi)一個(gè)已保存的文檔希望打開(kāi)的都是同一個(gè)文檔實(shí)例)其爵。
在UIAbility實(shí)例創(chuàng)建之前冒冬,允許開(kāi)發(fā)者為該實(shí)例創(chuàng)建一個(gè)唯一的字符串Key伸蚯,創(chuàng)建的UIAbility實(shí)例綁定Key之后,后續(xù)每次調(diào)用startAbility()方法時(shí)简烤,都會(huì)詢問(wèn)應(yīng)用使用哪個(gè)Key對(duì)應(yīng)的UIAbility實(shí)例來(lái)響應(yīng)startAbility()請(qǐng)求剂邮。運(yùn)行時(shí)由UIAbility內(nèi)部業(yè)務(wù)決定是否創(chuàng)建多實(shí)例,如果匹配有該UIAbility實(shí)例的Key乐埠,則直接拉起與之綁定的UIAbility實(shí)例抗斤,否則創(chuàng)建一個(gè)新的UIAbility實(shí)例。
- singleton(單實(shí)例模式)
-
UIAbility組件基本用法
UIAbility組件的基本用法包括:指定UIAbility的啟動(dòng)頁(yè)面以及獲取UIAbility的上下文UIAbilityContext丈咐。-
指定UIAbility的啟動(dòng)頁(yè)面
應(yīng)用中的UIAbility在啟動(dòng)過(guò)程中瑞眼,需要指定啟動(dòng)頁(yè)面,否則應(yīng)用啟動(dòng)后會(huì)因?yàn)闆](méi)有默認(rèn)加載頁(yè)面而導(dǎo)致白屏棵逊∩烁恚可以在UIAbility的onWindowStageCreate()生命周期回調(diào)中,通過(guò)WindowStage對(duì)象的loadContent()方法設(shè)置啟動(dòng)頁(yè)面辆影。import UIAbility from '@ohos.app.ability.UIAbility'; import Window from '@ohos.window'; export default class EntryAbility extends UIAbility { onWindowStageCreate(windowStage: Window.WindowStage) { // Main window is created, set main page for this ability windowStage.loadContent('pages/Index', (err, data) => { // ... }); } // ... }
-
獲取UIAbility的上下文信息
- 在UIAbility中可以通過(guò)this.context獲取UIAbility實(shí)例的上下文信息徒像。
let context = this.context;
- 在頁(yè)面中獲取UIAbility實(shí)例的上下文信息,包括導(dǎo)入依賴資源context模塊和在組件中定義一個(gè)context變量?jī)蓚€(gè)部分蛙讥。
也可以在導(dǎo)入依賴資源context模塊后锯蛀,在具體使用UIAbilityContext前進(jìn)行變量定義。import common from '@ohos.app.ability.common'; @Entry @Component struct Index { private context = getContext(this) as common.UIAbilityContext; startAbilityTest() { let want = { // Want參數(shù)信息 }; this.context.startAbility(want); } // 頁(yè)面展示 build() { // ... } }
startAbilityTest() { let context = getContext(this) as common.UIAbilityContext; let want = { // Want參數(shù)信息 }; context.startAbility(want); }
- 在UIAbility中可以通過(guò)this.context獲取UIAbility實(shí)例的上下文信息徒像。
-
-
UIAbility組件與UI的數(shù)據(jù)同步
基于HarmonyOS的應(yīng)用模型次慢,可以通過(guò)以下兩種方式來(lái)實(shí)現(xiàn)UIAbility組件與UI之間的數(shù)據(jù)同步旁涤。- EventHub:基于發(fā)布訂閱模式來(lái)實(shí)現(xiàn),事件需要先訂閱后發(fā)布迫像,訂閱者收到消息后進(jìn)行處理劈愚。
可類比為android中的EventBus - globalThis:ArkTS引擎實(shí)例內(nèi)部的一個(gè)全局對(duì)象,在ArkTS引擎實(shí)例內(nèi)部都能訪問(wèn)闻妓。
使用globalThis進(jìn)行數(shù)據(jù)同步[圖片上傳失敗...(image-852b6f-1697789591540)]- UIAbility和Page之間使用globalThis
globalThis為ArkTS引擎實(shí)例下的全局對(duì)象菌羽,可以通過(guò)globalThis綁定屬性/方法來(lái)進(jìn)行UIAbility組件與UI的數(shù)據(jù)同步。例如在UIAbility組件中綁定want參數(shù)由缆,即可在UIAbility對(duì)應(yīng)的UI界面上使用want參數(shù)信息注祖。- 調(diào)用startAbility()方法啟動(dòng)一個(gè)UIAbility實(shí)例時(shí),被啟動(dòng)的UIAbility創(chuàng)建完成后會(huì)進(jìn)入onCreate()生命周期回調(diào)均唉,且在onCreate()生命周期回調(diào)中能夠接受到傳遞過(guò)來(lái)的want參數(shù)氓轰,可以將want參數(shù)綁定到globalThis上。
import UIAbility from '@ohos.app.ability.UIAbility' export default class EntryAbility extends UIAbility { onCreate(want, launch) { globalThis.entryAbilityWant = want; // ... } // ... }
- 在UI界面中即可通過(guò)globalThis獲取到want參數(shù)信息浸卦。
let entryAbilityWant; @Entry @Component struct Index { aboutToAppear() { entryAbilityWant = globalThis.entryAbilityWant; } // 頁(yè)面展示 build() { // ... } }
- 調(diào)用startAbility()方法啟動(dòng)一個(gè)UIAbility實(shí)例時(shí),被啟動(dòng)的UIAbility創(chuàng)建完成后會(huì)進(jìn)入onCreate()生命周期回調(diào)均唉,且在onCreate()生命周期回調(diào)中能夠接受到傳遞過(guò)來(lái)的want參數(shù)氓轰,可以將want參數(shù)綁定到globalThis上。
- UIAbility和UIAbility之間使用globalThis
同理可類比上述使用方式 - UIAbility和ExtensionAbility之間使用globalThis
同理可類比上述使用方式 - globalThis使用的注意事項(xiàng)
- Stage模型下進(jìn)程內(nèi)的UIAbility組件共享ArkTS引擎實(shí)例署鸡,使用globalThis時(shí)需要避免存放相同名稱的對(duì)象。例如AbilityA和AbilityB可以使用globalThis共享數(shù)據(jù),在存放相同名稱的對(duì)象時(shí)靴庆,先存放的對(duì)象會(huì)被后存放的對(duì)象覆蓋时捌。
- FA模型因?yàn)槊總€(gè)UIAbility組件之間引擎隔離,不會(huì)存在該問(wèn)題炉抒。
- 對(duì)于綁定在globalThis上的對(duì)象奢讨,其生命周期與ArkTS虛擬機(jī)實(shí)例相同,
建議在使用完成之后將其賦值為null
焰薄,以減少對(duì)應(yīng)用內(nèi)存的占用拿诸。
- UIAbility和Page之間使用globalThis
- EventHub:基于發(fā)布訂閱模式來(lái)實(shí)現(xiàn),事件需要先訂閱后發(fā)布迫像,訂閱者收到消息后進(jìn)行處理劈愚。
UIAbility組件間交互(設(shè)備內(nèi))
方法類比原生Android
AbilityStage組件容器
AbilityStage是一個(gè)Module級(jí)別的組件容器,應(yīng)用的HAP在首次加載時(shí)會(huì)創(chuàng)建一個(gè)AbilityStage實(shí)例塞茅,可以對(duì)該Module進(jìn)行初始化等操作亩码。
AbilityStage與Module一一對(duì)應(yīng),即一個(gè)Module擁有一個(gè)AbilityStage野瘦。
我理解可以類比為Android的Application
具體創(chuàng)建步驟如下:
- 在工程Module對(duì)應(yīng)的ets目錄下描沟,右鍵選擇“New > Directory”,新建一個(gè)目錄并命名為myabilitystage鞭光。
- 在myabilitystage目錄吏廉,右鍵選擇“New > TypeScript File”,新建一個(gè)TypeScript文件并命名為MyAbilityStage.ts惰许。
- 打開(kāi)MyAbilityStage.ts文件席覆,導(dǎo)入AbilityStage的依賴包,自定義類繼承AbilityStage并加上需要的生命周期回調(diào)汹买,示例中增加了一個(gè)onCreate()生命周期回調(diào)娜睛。
- 在module.json5配置文件中,通過(guò)配置srcEntry參數(shù)來(lái)指定模塊對(duì)應(yīng)的代碼路徑卦睹,以作為HAP加載的入口。
{ "module": { "name": "entry", "type": "entry", "srcEntry": "./ets/myabilitystage/MyAbilityStage.ts", ... } }
AbilityStage擁有onCreate()生命周期回調(diào)和onAcceptWant()方库、onConfigurationUpdated()结序、onMemoryLevel()事件回調(diào)。
-
onCreate()
生命周期回調(diào):在開(kāi)始加載對(duì)應(yīng)Module的第一個(gè)UIAbility實(shí)例之前會(huì)先創(chuàng)建 AbilityStage纵潦,并在AbilityStage創(chuàng)建完成之后執(zhí)行其onCreate()生命周期回調(diào)徐鹤。AbilityStage模塊提供在Module加載的時(shí)候,通知開(kāi)發(fā)者邀层,可以在此進(jìn)行該Module的初始化(如資源預(yù)加載返敬,線程創(chuàng)建等)能力。 -
onAcceptWant()
事件回調(diào):UIAbility指定實(shí)例模式(specified)啟動(dòng)時(shí)候觸發(fā)的事件回調(diào)寥院,具體使用請(qǐng)參見(jiàn)UIAbility啟動(dòng)模式綜述劲赠。 -
onConfigurationUpdated()
事件回調(diào):當(dāng)系統(tǒng)全局配置發(fā)生變更時(shí)觸發(fā)的事件,系統(tǒng)語(yǔ)言、深淺色等凛澎,配置項(xiàng)目前均定義在Configuration類中霹肝。 -
onMemoryLevel()
事件回調(diào):當(dāng)系統(tǒng)調(diào)整內(nèi)存時(shí)觸發(fā)的事件。
應(yīng)用被切換到后臺(tái)時(shí)塑煎,系統(tǒng)會(huì)將在后臺(tái)的應(yīng)用保留在緩存中沫换。即使應(yīng)用處于緩存中,也會(huì)影響系統(tǒng)整體性能最铁。當(dāng)系統(tǒng)資源不足時(shí)讯赏,系統(tǒng)會(huì)通過(guò)多種方式從應(yīng)用中回收內(nèi)存,必要時(shí)會(huì)完全停止應(yīng)用冷尉,從而釋放內(nèi)存用于執(zhí)行關(guān)鍵任務(wù)漱挎。為了進(jìn)一步保持系統(tǒng)內(nèi)存的平衡,避免系統(tǒng)停止用戶的應(yīng)用進(jìn)程网严,可以在AbilityStage中的onMemoryLevel()生命周期回調(diào)中訂閱系統(tǒng)內(nèi)存的變化情況识樱,釋放不必要的資源。
應(yīng)用上下文Context
[圖片上傳失敗...(image-fac77d-1697789591541)]
訂閱進(jìn)程內(nèi)Ability生命周期變化
在應(yīng)用內(nèi)的DFX統(tǒng)計(jì)場(chǎng)景震束,如需要統(tǒng)計(jì)對(duì)應(yīng)頁(yè)面停留時(shí)間和訪問(wèn)頻率等信息怜庸,可以使用訂閱進(jìn)程內(nèi)Ability生命周期變化功能。
在進(jìn)程內(nèi)Ability生命周期變化時(shí)垢村,如創(chuàng)建割疾、可見(jiàn)/不可見(jiàn)、獲焦/失焦嘉栓、銷毀等宏榕,會(huì)觸發(fā)進(jìn)入相應(yīng)的回調(diào),其中返回的此次注冊(cè)監(jiān)聽(tīng)生命周期的ID(每次注冊(cè)該ID會(huì)自增+1侵佃,當(dāng)超過(guò)監(jiān)聽(tīng)上限數(shù)量2^63-1時(shí)麻昼,返回-1),以在UIAbilityContext中使用為例進(jìn)行說(shuō)明馋辈。
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';
const TAG: string = "[Example].[Entry].[EntryAbility]";
export default class EntryAbility extends UIAbility {
lifecycleId: number;
onCreate(want, launchParam) {
let abilityLifecycleCallback = {
onAbilityCreate(ability) {
console.info(TAG, "onAbilityCreate ability:" + JSON.stringify(ability));
},
onWindowStageCreate(ability, windowStage) {
console.info(TAG, "onWindowStageCreate ability:" + JSON.stringify(ability));
console.info(TAG, "onWindowStageCreate windowStage:" + JSON.stringify(windowStage));
},
onWindowStageActive(ability, windowStage) {
console.info(TAG, "onWindowStageActive ability:" + JSON.stringify(ability));
console.info(TAG, "onWindowStageActive windowStage:" + JSON.stringify(windowStage));
},
onWindowStageInactive(ability, windowStage) {
console.info(TAG, "onWindowStageInactive ability:" + JSON.stringify(ability));
console.info(TAG, "onWindowStageInactive windowStage:" + JSON.stringify(windowStage));
},
onWindowStageDestroy(ability, windowStage) {
console.info(TAG, "onWindowStageDestroy ability:" + JSON.stringify(ability));
console.info(TAG, "onWindowStageDestroy windowStage:" + JSON.stringify(windowStage));
},
onAbilityDestroy(ability) {
console.info(TAG, "onAbilityDestroy ability:" + JSON.stringify(ability));
},
onAbilityForeground(ability) {
console.info(TAG, "onAbilityForeground ability:" + JSON.stringify(ability));
},
onAbilityBackground(ability) {
console.info(TAG, "onAbilityBackground ability:" + JSON.stringify(ability));
},
onAbilityContinue(ability) {
console.info(TAG, "onAbilityContinue ability:" + JSON.stringify(ability));
}
}
// 1. 通過(guò)context屬性獲取applicationContext
let applicationContext = this.context.getApplicationContext();
// 2. 通過(guò)applicationContext注冊(cè)監(jiān)聽(tīng)?wèi)?yīng)用內(nèi)生命周期
this.lifecycleId = applicationContext.on("abilityLifecycle", abilityLifecycleCallback);
console.info(TAG, "register callback number: " + JSON.stringify(this.lifecycleId));
}
onDestroy() {
let applicationContext = this.context.getApplicationContext();
applicationContext.off("abilityLifecycle", this.lifecycleId, (error, data) => {
console.info(TAG, "unregister callback success, err: " + JSON.stringify(error));
});
}
}
信息傳遞載體Want
作用類比于Android中的Intent
Want
的類型
-
顯式Want:在啟動(dòng)Ability時(shí)指定了abilityName和bundleName的Want稱為顯式Want抚芦。
當(dāng)有明確處理請(qǐng)求的對(duì)象時(shí),通過(guò)提供目標(biāo)Ability所在應(yīng)用的包名信息(bundleName)迈螟,并在Want內(nèi)指定abilityName便可啟動(dòng)目標(biāo)Ability叉抡。顯式Want通常用于在當(dāng)前應(yīng)用開(kāi)發(fā)中啟動(dòng)某個(gè)已知的Ability。let wantInfo = { deviceId: '', // deviceId為空表示本設(shè)備 bundleName: 'com.example.myapplication', abilityName: 'FuncAbility', }
-
隱式的Want
在啟動(dòng)UIAbility時(shí)未指定abilityName的Want稱為隱式Want答毫。
當(dāng)請(qǐng)求處理的對(duì)象不明確時(shí)褥民,希望在當(dāng)前應(yīng)用中使用其他應(yīng)用提供的某個(gè)能力(通過(guò)skills標(biāo)簽定義),而不關(guān)心提供該能力的具體應(yīng)用洗搂,可以使用隱式Want消返。例如使用隱式Want描述需要打開(kāi)一個(gè)鏈接的請(qǐng)求载弄,而不關(guān)心通過(guò)具體哪個(gè)應(yīng)用打開(kāi),系統(tǒng)將匹配聲明支持該請(qǐng)求的所有應(yīng)用侦副。let wantInfo = { // uncomment line below if wish to implicitly query only in the specific bundle. // bundleName: 'com.example.myapplication', action: 'ohos.want.action.search', // entities can be omitted entities: [ 'entity.system.browsable' ], uri: 'https://www.test.com:8080/query/student', type: 'text/plain', };
- 根據(jù)系統(tǒng)中待匹配Ability的匹配情況不同侦锯,使用隱式Want啟動(dòng)Ability時(shí)會(huì)出現(xiàn)以下三種情況。
- 未匹配到滿足條件的Ability:?jiǎn)?dòng)失敗秦驯。
- 匹配到一個(gè)滿足條件的Ability:直接啟動(dòng)該Ability尺碰。
- 匹配到多個(gè)滿足條件的Ability(UIAbility):彈出選擇框讓用戶選擇。
- 調(diào)用方傳入的want參數(shù)中不帶有abilityName和bundleName译隘,則不允許通過(guò)隱式Want啟動(dòng)所有應(yīng)用的ServiceExtensionAbility亲桥。
- 調(diào)用方傳入的want參數(shù)中帶有bundleName,則允許使用startServiceExtensionAbility()方法隱式Want啟動(dòng)ServiceExtensionAbility固耘,默認(rèn)返回優(yōu)先級(jí)最高的ServiceExtensionAbility题篷,如果優(yōu)先級(jí)相同,返回第一個(gè)厅目。
- 根據(jù)系統(tǒng)中待匹配Ability的匹配情況不同侦锯,使用隱式Want啟動(dòng)Ability時(shí)會(huì)出現(xiàn)以下三種情況。
Want參數(shù)說(shuō)明在此
顯式Want與隱式Want匹配規(guī)則在此
常見(jiàn)action與entities
action
:表示調(diào)用方要執(zhí)行的通用操作(如查看番枚、分享、應(yīng)用詳情)损敷。在隱式Want中葫笼,您可定義該字段,配合uri或parameters來(lái)表示對(duì)數(shù)據(jù)要執(zhí)行的操作拗馒。如打開(kāi)路星,查看該uri數(shù)據(jù)。例如诱桂,當(dāng)uri為一段網(wǎng)址洋丐,action為ohos.want.action.viewData則表示匹配可查看該網(wǎng)址的Ability。在Want內(nèi)聲明action字段表示希望被調(diào)用方應(yīng)用支持聲明的操作挥等。在被調(diào)用方應(yīng)用配置文件skills字段內(nèi)聲明actions表示該應(yīng)用支持聲明操作友绝。
- 常見(jiàn)action
-
ACTION_HOME
:?jiǎn)?dòng)應(yīng)用入口組件的動(dòng)作,需要和ENTITY_HOME配合使用肝劲;系統(tǒng)桌面應(yīng)用圖標(biāo)就是顯式的入口組件迁客,點(diǎn)擊也是啟動(dòng)入口組件;入口組件可以配置多個(gè)涡相。 -
ACTION_CHOOSE
:選擇本地資源數(shù)據(jù),例如聯(lián)系人剩蟀、相冊(cè)等催蝗;系統(tǒng)一般對(duì)不同類型的數(shù)據(jù)有對(duì)應(yīng)的Picker應(yīng)用,例如聯(lián)系人和圖庫(kù)育特。 -
ACTION_VIEW_DATA
:查看數(shù)據(jù)丙号,當(dāng)使用網(wǎng)址uri時(shí)先朦,則表示顯示該網(wǎng)址對(duì)應(yīng)的內(nèi)容。 -
ACTION_VIEW_MULTIPLE_DATA
:發(fā)送多個(gè)數(shù)據(jù)記錄的操作犬缨。
-
entities
:表示目標(biāo)Ability的類別信息(如瀏覽器喳魏、視頻播放器),在隱式Want中是對(duì)action的補(bǔ)充怀薛。在隱式Want中刺彩,開(kāi)發(fā)者可定義該字段,來(lái)過(guò)濾匹配應(yīng)用的類別枝恋,例如必須是瀏覽器创倔。在Want內(nèi)聲明entities字段表示希望被調(diào)用方應(yīng)用屬于聲明的類別。在被調(diào)用方應(yīng)用配置文件skills字段內(nèi)聲明entites表示該應(yīng)用支持的類別焚碌。
- 常用entities
- ENTITY_DEFAULT:默認(rèn)類別無(wú)實(shí)際意義畦攘。
- ENTITY_HOME:主屏幕有圖標(biāo)點(diǎn)擊入口類別。
- ENTITY_BROWSABLE:指示瀏覽器類別十电。
使用顯式Want啟動(dòng)Ability在此
使用隱式Want打開(kāi)網(wǎng)址
應(yīng)用間使用Want分享數(shù)據(jù)
進(jìn)程模型
- 應(yīng)用中(同一包名)的所有UIAbility運(yùn)行在同一個(gè)獨(dú)立進(jìn)程中知押。
- WebView擁有獨(dú)立的渲染進(jìn)程。
基于HarmonyOS的進(jìn)程模型鹃骂,系統(tǒng)提供了公共事件機(jī)制用于一對(duì)多的通信場(chǎng)景台盯,公共事件發(fā)布者可能存在多個(gè)訂閱者同時(shí)接收事件。
公共事件訂閱概述
公共事件服務(wù)提供了動(dòng)態(tài)訂閱和靜態(tài)訂閱兩種訂閱方式。動(dòng)態(tài)訂閱與靜態(tài)訂閱最大的區(qū)別在于出吹,動(dòng)態(tài)訂閱是應(yīng)用運(yùn)行時(shí)行為付秕,而靜態(tài)訂閱是后臺(tái)服務(wù)無(wú)需處于運(yùn)行狀態(tài)。
- 動(dòng)態(tài)訂閱:指訂閱方在運(yùn)行時(shí)調(diào)用公共事件訂閱的API實(shí)現(xiàn)對(duì)公共事件的訂閱温亲,詳見(jiàn)動(dòng)態(tài)訂閱公共事件。
- 靜態(tài)訂閱:訂閱方通過(guò)配置文件聲明和實(shí)現(xiàn)繼承自StaticSubscriberExtensionAbility的類實(shí)現(xiàn)對(duì)公共事件的訂閱杯矩,詳見(jiàn)靜態(tài)訂閱公共事件栈虚。
動(dòng)態(tài)訂閱公共事件
場(chǎng)景介紹:
動(dòng)態(tài)訂閱是指當(dāng)應(yīng)用在運(yùn)行狀態(tài)時(shí)對(duì)某個(gè)公共事件進(jìn)行訂閱,在運(yùn)行期間如果有訂閱的事件發(fā)布那么訂閱了這個(gè)事件的應(yīng)用將會(huì)收到該事件及其傳遞的參數(shù)史隆。例如魂务,某應(yīng)用希望在其運(yùn)行期間收到電量過(guò)低的事件,并根據(jù)該事件降低其運(yùn)行功耗泌射,那么該應(yīng)用便可動(dòng)態(tài)訂閱電量過(guò)低事件粘姜,收到該事件后關(guān)閉一些非必要的任務(wù)來(lái)降低功耗。訂閱部分系統(tǒng)公共事件需要先申請(qǐng)權(quán)限熔酷,訂閱這些事件所需要的權(quán)限請(qǐng)見(jiàn)公共事件權(quán)限列表孤紧。
開(kāi)發(fā)步驟:
- 導(dǎo)入CommonEvent模塊。
import commonEvent from '@ohos.commonEventManager';
- 創(chuàng)建訂閱者信息拒秘,詳細(xì)的訂閱者信息數(shù)據(jù)類型及包含的參數(shù)請(qǐng)見(jiàn)CommonEventSubscribeInfo文檔介紹号显。
// 用于保存創(chuàng)建成功的訂閱者對(duì)象臭猜,后續(xù)使用其完成訂閱及退訂的動(dòng)作 let subscriber = null; // 訂閱者信息 let subscribeInfo = { events: ["usual.event.SCREEN_OFF"], // 訂閱滅屏公共事件 }
- 創(chuàng)建訂閱者,保存返回的訂閱者對(duì)象subscriber押蚤,用于執(zhí)行后續(xù)的訂閱蔑歌、退訂等操作。
// 創(chuàng)建訂閱者回調(diào) commonEvent.createSubscriber(subscribeInfo, (err, data) => { if (err) { console.error(`[CommonEvent] CreateSubscriberCallBack err=${JSON.stringify(err)}`); } else { console.info(`[CommonEvent] CreateSubscriber success`); subscriber = data; // 訂閱公共事件回調(diào) } })
- 創(chuàng)建訂閱回調(diào)函數(shù)揽碘,訂閱回調(diào)函數(shù)會(huì)在接收到事件時(shí)觸發(fā)次屠。訂閱回調(diào)函數(shù)返回的data內(nèi)包含了公共事件的名稱、發(fā)布者攜帶的數(shù)據(jù)等信息钾菊,公共事件數(shù)據(jù)的詳細(xì)參數(shù)和數(shù)據(jù)類型請(qǐng)見(jiàn)CommonEventData文檔介紹帅矗。
// 訂閱公共事件回調(diào) if (subscriber !== null) { commonEvent.subscribe(subscriber, (err, data) => { if (err) { console.error(`[CommonEvent] SubscribeCallBack err=${JSON.stringify(err)}`); } else { console.info(`[CommonEvent] SubscribeCallBack data=${JSON.stringify(data)}`); } }) } else { console.error(`[CommonEvent] Need create subscriber`); }
靜態(tài)訂閱公共事件(僅對(duì)系統(tǒng)應(yīng)用開(kāi)放)
靜態(tài)訂閱者在未接收訂閱的目標(biāo)事件時(shí),處于未拉起狀態(tài)煞烫,當(dāng)系統(tǒng)或應(yīng)用發(fā)布了指定的公共事件后浑此,靜態(tài)訂閱者將被拉起,并執(zhí)行onReceiveEvent回調(diào)滞详,開(kāi)發(fā)者可通過(guò)在onReceiveEvent回調(diào)中執(zhí)行業(yè)務(wù)邏輯凛俱,實(shí)現(xiàn)當(dāng)應(yīng)用接收到特定公共事件時(shí)執(zhí)行業(yè)務(wù)邏輯的目的。例如料饥,某應(yīng)用希望在設(shè)備開(kāi)機(jī)的時(shí)候執(zhí)行一些初始化任務(wù)蒲犬,那么該應(yīng)用可以靜態(tài)訂閱開(kāi)機(jī)事件,在收到開(kāi)機(jī)事件后會(huì)拉起該應(yīng)用岸啡,然后執(zhí)行初始化任務(wù)原叮。靜態(tài)訂閱是通過(guò)配置文件聲明和實(shí)現(xiàn)繼承自StaticSubscriberExtensionAbility的類實(shí)現(xiàn)對(duì)公共事件的訂閱。需要注意的是巡蘸,靜態(tài)訂閱公共事件對(duì)系統(tǒng)功耗有一定影響奋隶,建議謹(jǐn)慎使用。
取消動(dòng)態(tài)訂閱公共事件
動(dòng)態(tài)訂閱者完成業(yè)務(wù)需要時(shí)悦荒,需要主動(dòng)取消訂閱唯欣,訂閱者通過(guò)調(diào)用unsubscribe()方法取消訂閱事件。
開(kāi)發(fā)步驟:
- 導(dǎo)入CommonEvent模塊搬味。
import commonEvent from '@ohos.commonEventManager';
- 根據(jù)動(dòng)態(tài)訂閱公共事件章節(jié)的步驟來(lái)訂閱某個(gè)事件境氢。
- 調(diào)用CommonEvent中的unsubscribe方法取消訂閱某事件。
// subscriber為訂閱事件時(shí)創(chuàng)建的訂閱者對(duì)象 if (subscriber !== null) { commonEvent.unsubscribe(subscriber, (err) => { if (err) { console.error(`[CommonEvent] UnsubscribeCallBack err=${JSON.stringify(err)}`) } else { console.info(`[CommonEvent] Unsubscribe`) subscriber = null } }) }
公共事件發(fā)布
當(dāng)需要發(fā)布某個(gè)自定義公共事件時(shí)碰纬,可以通過(guò)publish()方法發(fā)布事件萍聊。發(fā)布的公共事件可以攜帶數(shù)據(jù),供訂閱者解析并進(jìn)行下一步處理悦析。
接口說(shuō)明
-
發(fā)布不攜帶信息的公共事件
(不攜帶信息的公共事件寿桨,只能發(fā)布無(wú)序公共事件。)- 導(dǎo)入CommonEvent模塊她按。
import commonEvent from '@ohos.commonEventManager';
- 傳入需要發(fā)布的事件名稱和回調(diào)函數(shù)牛隅,發(fā)布事件。
// 發(fā)布公共事件 commonEvent.publish("usual.event.SCREEN_OFF", (err) => { if (err) { console.error(`[CommonEvent] PublishCallBack err=${JSON.stringify(err)}`); } else { console.info(`[CommonEvent] Publish success`); } })
- 導(dǎo)入CommonEvent模塊她按。
-
發(fā)布攜帶信息的公共事件
:
攜帶信息的公共事件酌泰,可以發(fā)布為無(wú)序公共事件媒佣、有序公共事件和粘性事件,可以通過(guò)參數(shù)CommonEventPublishData的isOrdered陵刹、isSticky的字段進(jìn)行設(shè)置默伍。- 導(dǎo)入CommonEvent模塊。
import commonEvent from '@ohos.commonEventManager';
- 傳入需要發(fā)布的事件名稱和回調(diào)函數(shù)衰琐,發(fā)布事件也糊。
// 公共事件相關(guān)信息 let options = { code: 1, // 公共事件的初始代碼 data: "initial data", // 公共事件的初始數(shù)據(jù) }
- 傳入需要發(fā)布的事件名稱、需要發(fā)布的指定信息和回調(diào)函數(shù)羡宙,發(fā)布事件狸剃。
// 發(fā)布公共事件 commonEvent.publish("usual.event.SCREEN_OFF", options, (err) => { if (err) { console.error('[CommonEvent] PublishCallBack err=' + JSON.stringify(err)); } else { console.info('[CommonEvent] Publish success') } })
- 導(dǎo)入CommonEvent模塊。
線程模型
線程模型概述
HarmonyOS應(yīng)用中每個(gè)進(jìn)程都會(huì)有一個(gè)主線程,主線程有如下職責(zé):
- 執(zhí)行UI繪制狗热;
- 管理主線程的ArkTS引擎實(shí)例钞馁,使多個(gè)UIAbility組件能夠運(yùn)行在其之上;
- 管理其他線程(例如Worker線程)的ArkTS引擎實(shí)例匿刮,例如啟動(dòng)和終止其他線程僧凰;
- 分發(fā)交互事件;
- 處理應(yīng)用代碼的回調(diào)熟丸,包括事件處理和生命周期管理训措;
- 接收Worker線程發(fā)送的消息;
除主線程外光羞,還有一類與主線程并行的獨(dú)立線程Worker绩鸣,主要用于執(zhí)行耗時(shí)操作,但不可以直接操作UI狞山。Worker線程在主線程中創(chuàng)建全闷,與主線程相互獨(dú)立。最多可以創(chuàng)建8個(gè)Worker
基于HarmonyOS的線程模型萍启,不同的業(yè)務(wù)功能運(yùn)行在不同的線程上总珠,業(yè)務(wù)功能的交互就需要線程間通信。線程間通信目前主要有Emitter
和Worker
兩種方式勘纯,其中Emitter主要適用于線程間的事件同步局服, Worker主要用于新開(kāi)一個(gè)線程執(zhí)行耗時(shí)任務(wù)。
- 注意: Stage模型只提供了主線程和Worker線程驳遵,Emitter主要用于主線程內(nèi)或者主線程和Worker線程的事件同步淫奔。
使用Emitter進(jìn)行線程間通信
Emitter主要提供線程間發(fā)送和處理事件的能力,包括對(duì)持續(xù)訂閱事件或單次訂閱事件的處理堤结、取消訂閱事件唆迁、發(fā)送事件到事件隊(duì)列等鸭丛。
- 開(kāi)發(fā)步驟
- 訂閱事件
import emitter from "@ohos.events.emitter"; // 定義一個(gè)eventId為1的事件 let event = { eventId: 1 }; // 收到eventId為1的事件后執(zhí)行該回調(diào) let callback = (eventData) => { console.info('event callback'); }; // 訂閱eventId為1的事件 emitter.on(event, callback);
- 發(fā)送事件
import emitter from "@ohos.events.emitter"; // 定義一個(gè)eventId為1的事件,事件優(yōu)先級(jí)為L(zhǎng)ow let event = { eventId: 1, priority: emitter.EventPriority.LOW }; let eventData = { data: { "content": "c", "id": 1, "isEmpty": false, } }; // 發(fā)送eventId為1的事件唐责,事件內(nèi)容為eventData emitter.emit(event, eventData);
- 訂閱事件
使用Worker進(jìn)行線程間通信
Worker是與主線程并行的獨(dú)立線程鳞溉。創(chuàng)建Worker的線程被稱為宿主線程,Worker工作的線程被稱為Worker線程鼠哥。創(chuàng)建Worker時(shí)傳入的腳本文件在Worker線程中執(zhí)行熟菲,通常在Worker線程中處理耗時(shí)的操作,需要注意的是朴恳,Worker中不能直接更新Page抄罕。
- 開(kāi)發(fā)步驟
- 在工程的模塊級(jí)build-profile.json5文件的buildOption屬性中添加配置信息。
"buildOption": { "sourceOption": { "workers": [ "./src/main/ets/workers/worker.ts" ] } }
- 根據(jù)build-profile.json5中的配置創(chuàng)建對(duì)應(yīng)的worker.ts文件于颖。
import worker from '@ohos.worker'; let parent = worker.workerPort; // 處理來(lái)自主線程的消息 parent.onmessage = function(message) { console.info("onmessage: " + message) // 發(fā)送消息到主線程 parent.postMessage("message from worker thread.") }
- 主線程中使用如下方式初始化和使用worker呆贿。
- Stage模型
import worker from '@ohos.worker'; let wk = new worker.ThreadWorker("entry/ets/workers/worker.ts"); // 發(fā)送消息到worker線程 wk.postMessage("message from main thread.") // 處理來(lái)自worker線程的消息 wk.onmessage = function(message) { console.info("message from worker: " + message) // 根據(jù)業(yè)務(wù)按需停止worker線程 wk.terminate() }
- Stage模型
- 在工程的模塊級(jí)build-profile.json5文件的buildOption屬性中添加配置信息。
- 說(shuō)明:
build-profile.json5中配置的worker.ts的相對(duì)路徑都為./src/main/ets/workers/worker.ts時(shí),在Stage模型下創(chuàng)建worker需要傳入路徑entry/ets/workers/worker.ts森渐;在FA模型下創(chuàng)建worker需要傳入路徑../workers/worker.ts榨崩。
主線程與Worker線程間支持的數(shù)據(jù)類型參考序列化支持類型。
傳遞通過(guò)自定義class創(chuàng)建出來(lái)的object時(shí)章母,不會(huì)發(fā)生序列化錯(cuò)誤母蛛,但是自定義class的屬性(如Function)無(wú)法通過(guò)序列化傳遞。
Worker存在數(shù)量限制乳怎,當(dāng)前支持最多同時(shí)存在8個(gè)Worker彩郊。
主動(dòng)銷毀Worker可以調(diào)用新創(chuàng)建Worker對(duì)象的terminate()或workerPort.close()方法。
自API version 9版本開(kāi)始蚪缀,若Worker處于已經(jīng)銷毀或正在銷毀等非運(yùn)行狀態(tài)時(shí)秫逝,調(diào)用其功能接口,會(huì)拋出相應(yīng)的BusinessError询枚。
Worker的創(chuàng)建和銷毀耗費(fèi)性能违帆,建議管理已創(chuàng)建的Worker并重復(fù)使用。
創(chuàng)建Worker工程時(shí)金蜀,new worker.Worker構(gòu)造函數(shù)和new worker.ThreadWorker構(gòu)造函數(shù)不能同時(shí)使用刷后,否則將導(dǎo)致工程中Worker的功能異常。自API version 9版本開(kāi)始渊抄,建議使用new worker.ThreadWorker構(gòu)造函數(shù)尝胆,在API version 8及之前的版本,建議使用new worker.Worker構(gòu)造函數(shù)护桦。
創(chuàng)建Worker工程時(shí)含衔,在Worker線程的文件中(比如本文中worker.ts)不能導(dǎo)入任何有關(guān)構(gòu)建UI的方法(比如ETS文件等),否則會(huì)導(dǎo)致Worker的功能失效。排查方式:解壓生成的Hap包贪染,在創(chuàng)建Worker線程的文件目錄中找到"worker.js"缓呛,全局搜索"View"關(guān)鍵字。如果存在該關(guān)鍵字杭隙,說(shuō)明在worker.js中打包進(jìn)去了構(gòu)建UI的方法强经,會(huì)導(dǎo)致Worker的功能失效,建議在創(chuàng)建Worker線程的文件中修改 "import “xxx” from src"中src的目錄層級(jí)寺渗。
線程間通信時(shí)傳遞的數(shù)據(jù)量最大限制為16M。
UI開(kāi)發(fā)
方舟開(kāi)發(fā)框架(ArkUI)概述
開(kāi)發(fā)布局
線性布局(Row兰迫、Column)
如果布局內(nèi)子元素超過(guò)1個(gè)信殊,且能夠以某種方式線性排列時(shí)優(yōu)先考慮此布局。層疊布局(Stack)
組件需要有堆疊效果時(shí)優(yōu)先考慮此布局汁果,層疊布局的堆疊效果不會(huì)占用或影響其他同容器內(nèi)子組件的布局空間涡拘。例如Panel作為子組件彈出時(shí)將其他組件覆蓋更為合理,則優(yōu)先考慮在外層使用堆疊布局据德。彈性布局(Flex)
彈性布局是與線性布局類似的布局方式鳄乏。區(qū)別在于彈性布局默認(rèn)能夠使子組件壓縮或拉伸。在子組件需要計(jì)算拉伸或壓縮比例時(shí)優(yōu)先使用此布局棘利,可使得多個(gè)容器內(nèi)子組件能有更好的視覺(jué)上的填充容器效果橱野。相對(duì)布局(RelativeContainer)
相對(duì)布局是在二維空間中的布局方式,不需要遵循線性布局的規(guī)則善玫,布局方式更為自由水援。通過(guò)在子組件上設(shè)置錨點(diǎn)規(guī)則(AlignRules)使子組件能夠?qū)⒆约涸跈M軸、縱軸中的位置與容器或容器內(nèi)其他子組件的位置對(duì)齊茅郎。設(shè)置的錨點(diǎn)規(guī)則可以天然支持子元素壓縮蜗元、拉伸,堆疊或形成多行效果系冗。在頁(yè)面元素分布復(fù)雜或通過(guò)線性布局會(huì)使容器嵌套層數(shù)過(guò)深時(shí)推薦使用奕扣。柵格布局(GridRow、GridCol)
柵格是多設(shè)備場(chǎng)景下通用的輔助定位工具掌敬,通過(guò)將空間分割為有規(guī)律的柵格惯豆。柵格不同于網(wǎng)格布局固定的空間劃分,它可以實(shí)現(xiàn)不同設(shè)備下不同的布局奔害,空間劃分更隨心所欲循帐,從而顯著降低適配不同屏幕尺寸的設(shè)計(jì)及開(kāi)發(fā)成本,使得整體設(shè)計(jì)和開(kāi)發(fā)流程更有秩序和節(jié)奏感舀武,同時(shí)也保證多設(shè)備上應(yīng)用顯示的協(xié)調(diào)性和一致性拄养,提升用戶體驗(yàn)。推薦手機(jī)、大屏瘪匿、平板等不同設(shè)備跛梗,內(nèi)容相同但布局不同時(shí)使用。媒體查詢(@ohos.mediaquery)
媒體查詢可根據(jù)不同設(shè)備類型或同設(shè)備不同狀態(tài)修改應(yīng)用的樣式棋弥。例如根據(jù)設(shè)備和應(yīng)用的不同屬性信息設(shè)計(jì)不同的布局核偿,以及屏幕發(fā)生動(dòng)態(tài)改變時(shí)更新應(yīng)用的頁(yè)面布局。列表(List)
使用列表可以輕松高效地顯示結(jié)構(gòu)化顽染、可滾動(dòng)的信息漾岳。在ArkUI中,列表具有垂直和水平布局能力和自適應(yīng)交叉軸方向上排列個(gè)數(shù)的布局能力粉寞,超出屏幕時(shí)可以滾動(dòng)尼荆。列表適合用于呈現(xiàn)同類數(shù)據(jù)類型或數(shù)據(jù)類型集,例如圖片和文本唧垦。網(wǎng)格(Grid)
網(wǎng)格布局具有較強(qiáng)的頁(yè)面均分能力捅儒,子組件占比控制能力,是一種重要自適應(yīng)布局振亮。網(wǎng)格布局可以控制元素所占的網(wǎng)格數(shù)量巧还、設(shè)置子組件橫跨幾行或者幾列,當(dāng)網(wǎng)格容器尺寸發(fā)生變化時(shí)坊秸,所有子組件以及間距等比例調(diào)整麸祷。推薦在需要按照固定比例或者均勻分配空間的布局場(chǎng)景下使用,例如計(jì)算器褒搔、相冊(cè)摇锋、日歷等。輪播(Swiper)
輪播組件通常用于實(shí)現(xiàn)廣告輪播站超、圖片預(yù)覽荸恕、可滾動(dòng)應(yīng)用等。
添加組件
添加常用組件
- 按鈕(Button)
- 單選框(Radio)
- 切換按鈕(Toggle)
- 進(jìn)度條(Progress)
- 文本顯示(Text/Span)
- 文本輸入(TextInput/TextArea)
- 自定義彈窗(CustomDialog)
- 視頻播放(Video)
- XComponent
添加氣泡和菜單
設(shè)置頁(yè)面路由和組件導(dǎo)航
頁(yè)面路由router
組件導(dǎo)航
Navigation
Navigation組件一般作為頁(yè)面的根容器死相,包括單頁(yè)面融求、分欄和自適應(yīng)三種顯示模式。同時(shí)算撮,Navigation提供了屬性來(lái)設(shè)置頁(yè)面的標(biāo)題欄生宛、工具欄、導(dǎo)航欄等肮柜。-
Tabs
當(dāng)頁(yè)面信息較多時(shí)陷舅,為了讓用戶能夠聚焦于當(dāng)前顯示的內(nèi)容,需要對(duì)頁(yè)面內(nèi)容進(jìn)行分類审洞,提高頁(yè)面空間利用率莱睁。Tabs組件可以在一個(gè)頁(yè)面內(nèi)快速實(shí)現(xiàn)視圖內(nèi)容的切換,一方面提升查找信息的效率,另一方面精簡(jiǎn)用戶單次獲取到的信息量仰剿。基本布局
底部導(dǎo)航
頂部導(dǎo)航
側(cè)邊導(dǎo)航
限制導(dǎo)航欄的滑動(dòng)切換
固定導(dǎo)航欄
滾動(dòng)導(dǎo)航欄
自定義導(dǎo)航欄
切換至指定頁(yè)簽
滑動(dòng)切換導(dǎo)航欄
顯示圖形
使用動(dòng)畫(huà)
頁(yè)面內(nèi)動(dòng)畫(huà)
支持交互事件
使用通用事件
- 觸屏事件
- 點(diǎn)擊事件
- 拖拽事件
- 觸摸事件
- 鍵鼠事件
- 鼠標(biāo)事件
- 按鍵事件
- 焦點(diǎn)事件
使用手勢(shì)事件
Web相關(guān)
ArkTS語(yǔ)言基礎(chǔ)類庫(kù)概述
- 并發(fā)
- 容器類庫(kù)
安全
網(wǎng)絡(luò)與連接
電話服務(wù)
數(shù)據(jù)管理
文件管理
后臺(tái)任務(wù)
設(shè)備管理
通知
窗口管理
WebGL
WebGL的全稱為Web Graphic Library(網(wǎng)頁(yè)圖形庫(kù))创淡,主要用于交互式渲染2D圖形和3D圖形。目前HarmonyOS中使用的WebGL是基于OpenGL裁剪的OpenGL ES南吮,可以在HTML5的canvas元素對(duì)象中使用琳彩,無(wú)需使用插件,支持跨平臺(tái)部凑。WebGL程序是由JavaScript代碼組成的露乏,其中使用的API可以利用用戶設(shè)備提供的GPU硬件完成圖形渲染和加速。更多信息請(qǐng)參考WebGL?標(biāo)準(zhǔn)涂邀。