鴻蒙HarmonyOS UI框架關鍵技術(shù)解析
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
HarmonyOS UI框架提供了界面繪制相關的處理方法,例如:圖形控件、頁面布局和窗口管理(如圖1所示)。

圖1 UI框架
HarmonyOS UI框架采用的是ACE(Ability Crossplatform Environment)框架(如圖2所示)。
ACE是一個應用開發(fā)框架,在OS架構(gòu)之上,屬于上層框架,目前支持JAVA和JS語言開發(fā),兩種語言框架具體區(qū)別如下:
1. JAVA UI框架提供了細粒度的UI編程接口,使應用開發(fā)更加靈活,元素以組件、布局的形式將界面繪制在窗口上。
2. JS UI框架采用類HTML和CSS聲明式編程語言作為頁面布局和頁面樣式的開發(fā)語言,頁面業(yè)務邏輯則支持ECMAScript 規(guī)范的JavaScript語言。JS UI框架提供的聲明式編程,可以讓開發(fā)者避免編寫UI狀態(tài)切換的代碼,視圖配置信息更加直觀。

圖2 ACE UI框架
HarmonyOS UI框架關鍵技術(shù)
ACE JAVA UI框架
應用由Ability構(gòu)成。Ability可以分為FA(Feature Ability)和PA(Particle Ability)兩種類型。
❖Feature Ability(簡稱FA)支持Page Ability,一般用于用戶交互,在屏幕上顯示一個用戶界面,該界面用來顯示所有可被用戶查看和交互的內(nèi)容。用戶界面由UI元素構(gòu)成,通常包含布局、控件等形式,且元素支持設置資源和動畫。
❖Particle Ability支持Data Ability(數(shù)據(jù)訪問)和Service Ability(后臺服務),一般用于后臺業(yè)務邏輯的實現(xiàn)。

圖3 JAVA UI
一 . 界面構(gòu)成
每個用戶界面的UI元素由組件樹構(gòu)成,即由Component和ComponentContainer對象構(gòu)成(如圖4所示)。
Java UI框架提供了一部分Component和ComponentContainer的具體子類,即創(chuàng)建用戶界面(UI)的各類組件,包括一些常用的組件(比如:文本、按鈕、圖片、列表等)和常用的布局(比如:DirectionalLayout和DependentLayout)等。用戶可通過組件進行交互操作,并獲得響應。
● Component: 提供內(nèi)容顯示,是界面中所有組件的基類。
●ComponentContainer: 作為容器容納Component或ComponentContainer對象,并對它們進行布局。

圖4 JAVA UI組件樹
二.Ability
Page Ability的構(gòu)成
一個Page可以由一個或多個AbilitySlice構(gòu)成,AbilitySlice是指應用的單個頁面及其控制邏輯的總和。

圖5 Page Ability構(gòu)成
Ability的生命周期
● onStart()
當系統(tǒng)首次創(chuàng)建Page實例時,觸發(fā)該回調(diào)。
● onActive()
Page會在進入INACTIVE狀態(tài)后來到前臺,然后系統(tǒng)調(diào)用此回調(diào)。Page在此之后進入ACTIVE狀態(tài),該狀態(tài)是應用與用戶交互的狀態(tài)。
● onInactive()
當Page失去焦點時,系統(tǒng)將調(diào)用此回調(diào),此后Page進入INACTIVE狀態(tài)。
● onBackground()
如果Page不再對用戶可見,系統(tǒng)將調(diào)用此回調(diào),此后Page進入BACKGROUND狀態(tài)。
● onForeground()
處于BACKGROUND狀態(tài)的Page仍然駐留在內(nèi)存中,當重新回到前臺時,系統(tǒng)將先調(diào)用onForeground()回調(diào)通知開發(fā)者,而后Page的生命周期狀態(tài)回到INACTIVE狀態(tài)。
● onStop()
下面是幾個主要生命周期函數(shù)。
系統(tǒng)將要銷毀Page時,將會觸發(fā)此回調(diào)函數(shù)。
具體生命周期流程如下圖所示:

圖6 Java FA生命周期
Java Ability路由
Java FA提供三種路由方式:
- Ability間的跳轉(zhuǎn)(不同Ability)
- Ability內(nèi)部AbilitySlice間跳轉(zhuǎn)
- 跨設備跳轉(zhuǎn)

圖7 Java FA路由
1.Ability間跳轉(zhuǎn)(不同Ability):
一個Ability跳轉(zhuǎn)到另一個Ability時,根據(jù)不同的action選擇不同的Slice。示例代碼如下:
- Intent intent = new Intent();
- Operation operation = new Intent.OperationBuilder()
- .withAction("action2")
- .build();
- intent.setOperation(operation);
- startAbility(intent);
如圖7為示,Ability3通過addActionRoute接口配置了3條路由規(guī)則Router:
- action1路由到AbilitySlice1;
- action2路由到AbilitySlice2;
- action3路由到AbilitySlice3。
Ability1和Ability2分別通過startAbility跳轉(zhuǎn)到Ability3,再根據(jù)三條路由規(guī)則選擇各自對應的AbilitySlice。
其時序如圖8所示:

圖8 Ability間跳轉(zhuǎn)
- Ability2初始化時通過addActionRoute接口設置了路由規(guī)則。
- Ability1通過startAbilityForResult跳轉(zhuǎn)到Ability2時,Ability2根據(jù)action選擇AbilitySlice1或AbilitySlice2。
- 當Ability2關閉返回時,Ability1通過onAbilityResult()回調(diào)方法,對請求結(jié)果進行處理。
2.Ability內(nèi)部AbilitySlice間跳轉(zhuǎn)
當發(fā)起導航的AbilitySlice和導航目標的AbilitySlice處于同一個Ability時,可以通過present()或presentForResult()方法實現(xiàn)導航。
同一個Page內(nèi)的AbilitySlice導航,只需要指定目標AbilitySlice名稱即可。AbilitySlice1通過present方法發(fā)起跳轉(zhuǎn),并指定目標名為AbilitySlice2,則跳轉(zhuǎn)結(jié)果為顯示AbilitySlice2。示例代碼如下:
- present(new AbilitySlice2(), new Intent());
其時序如圖9所示:

圖9 AbilitySlice間跳轉(zhuǎn)
- Ability3包含AbilitySlice1、AbilitySlice2、AbilitySlice3三個AbilitySlice,初始化時通過setMainRoute方法設置了默認界面為AbilitySlice1。
- AbilitySlice1可通過present()發(fā)起導航到AbilitySlice2,導航完成后界面顯示AbilitySlice2。
- 若AbilitySlice1希望從導航目標AbilitySlice3返回時,能夠獲得其返回結(jié)果,則可使用presentForResult()實現(xiàn)導航。當AbilitySlice3返回時,系統(tǒng)將回調(diào)onResult()給AbilitySlice1來接收和處理返回結(jié)果,其中返回結(jié)果由AbilitySlice3在其生命周期內(nèi)通過setResult()進行設置。
3.跨設備跳轉(zhuǎn)
Ability也支持跨設備的路由,即目標Ability即可以是本地設備的Ability,亦可以是同一用戶的不同設備,只需在startAbility進行路由時通過withDeviceId指定對端的設備id即可。
如圖10所示:Ability1通過action選擇到Ability2的路由,且通過withDeviceId指定了目標設備B,則最終結(jié)果為設備B上Ability2的對應界面被拉起顯示。

圖10 跨設備路由
4.資源管理
JAVA UI框架下的資源管理目錄如下:

圖12 JAVA UI下資源目錄結(jié)構(gòu)


示例代碼如下:
Java文件中,引用string.json文件中類型為“String”、名稱為“app_name”的資源:
- ohos.global.resource.ResourceManager resManager = this.getResourceManager();
- String result = resManager.getElement(ResourceTable.String_app_name).getString();
XML文件中,引用string.json文件中類型為“String”、名稱為“app_name”的資源:
- <?xml version="1.0" encoding="utf-8"?>
- <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos"
- ohos:width="match_parent"
- ohos:height="match_parent"
- ohos:orientation="vertical">
- <Text ohos:text="$string:app_name"/>
- </DirectionalLayout>
ACE JS UI框架
JS UI框架是一種跨設備的高性能UI開發(fā)框架,支持聲明式編程和跨設備多態(tài)UI。它包括應用層(Application)、前端框架層(Framework)、引擎層(Engine)和平臺適配層(Porting Layer)。

圖13 JS UI框架
❖ Application
應用層表示開發(fā)者使用JS UI框架開發(fā)的FA應用。
❖ Framework
前端框架層主要完成前端頁面解析,以及提供MVVM(ModelViewViewModel)開發(fā)模式、頁面路由機制和自定義組件等能力。
❖ Engine
引擎層主要提供動畫解析、DOM(Document Object Model)樹構(gòu)建、布局計算、渲染命令構(gòu)建與繪制、事件管理和平臺channel機制等能力。
❖ Porting Layer
適配層主要完成對平臺層進行抽象,提供具體抽象接口,可以對接到不同系統(tǒng)平臺。比如:事件對接、渲染管線對接和系統(tǒng)生命周期對接等。
1.界面構(gòu)成
每個用戶界面的 UI布局由HML+CSS文件完成,響應及業(yè)務邏輯由JS文件完成。

圖14 JS應用構(gòu)成
● HML(HarmonyOS Markup Language)是一套類HTML的標記語言,通過組件,事件構(gòu)建出頁面的內(nèi)容。頁面具備數(shù)據(jù)綁定、事件綁定、列表渲染、條件渲染和邏輯控制等高級能力。
● CSS是描述HML頁面結(jié)構(gòu)的樣式語言。
● JS文件用來定義HML頁面的業(yè)務邏輯,支持ECMA規(guī)范的JavaScript語言。
示例代碼如下:

圖15 JS UI代碼示例
其中,UI布局由HML和CSS完成:
HML里<div>頁簽設置了界面組件,組件樣式由container類定義,組件中包含文本控件text,文本內(nèi)容由{{title}}填充,并給該文本控件設置了點擊響應事件onclick,在控件被點擊時執(zhí)行change方法。
CSS里聲明了樣式,如container類設置了HML里
對應的業(yè)務邏輯在JavaScript完成:
初始化時,將title設置為“hello world”,即刷新了文本控件text的填充內(nèi)容{{title}}。
組件(Component)是構(gòu)建頁面的核心,每個組件通過對數(shù)據(jù)和方法的簡單封裝,實現(xiàn)獨立的可視、可交互功能單元。

圖16 組件分類
關于【組件詳情】,請參考官網(wǎng)資料:
● 組件詳情
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-js-building-ui-component-0000000000500580
2.Ability
JS UI的Ability生命周期
下面是幾個主要生命周期函數(shù)。
● onCreate ()
當應用創(chuàng)建時調(diào)用。(應用的生命周期)
● onInit ()
頁面數(shù)據(jù)初始化完成時觸發(fā),只觸發(fā)一次。
● onReady ()
頁面創(chuàng)建完成時觸發(fā),只觸發(fā)一次。
● onShow ()
頁面顯示時觸發(fā)。
● onHide ()
頁面消失時觸發(fā)。
● onDestroy ()
頁面銷毀時觸發(fā)。
具體生命周期流程如下圖所示:

圖17 JS FA頁面生命周期
JS Ability路由
JS FA也提供了三種路由方式:
- Ability間的跳轉(zhuǎn)
- Ability內(nèi)部JS page間跳轉(zhuǎn)
- 跨設備跳轉(zhuǎn)

圖18 JS FA路由
1.Ability間的跳轉(zhuǎn)
JS中的Ability繼承自AceAbility。
AceAbility間的跳轉(zhuǎn)JS接口通過FeatureAbility.startAbility完成:
- let actionData = {
- uri: 'www.huawei.com'
- };
- let target = {
- bundleName: "com.example.harmonydevsample",
- abilityName: "com.example.harmonydevsample.EntryJSApiAbility",
- data: actionData
- };
- let result = await FeatureAbility.startAbility(target);
- let ret = JSON.parse(result);
- if (ret.code == 0) {
- console.log('success');
- } else {
- console.log('cannot start browing service, reason: ' + ret.data);
- }
2.Ability內(nèi)部JS page間跳轉(zhuǎn)
JS的Ability中可有多個不同頁面,每個界面是一個Js Page(在pages目錄下定義),如下面的ability包含了index和detail 2個頁面:
- {
- ...
- "pages": [
- "pages/index/index",
- "pages/detail/detail"
- ]
- ...
- }
JS Page間可通過router跳轉(zhuǎn),例如跳轉(zhuǎn)到detail的頁面:
- import router from '@system.router';
- router.push({
- uri: "pages/detail/detail",
- params: {
- eventId: item,
- }
- });
3.跨設備跳轉(zhuǎn)
跨設備跳轉(zhuǎn)路由原理同Java UI上跨設備一樣,只是JS UI中提供的是對應JS的接口:
- FeatureAbility.startAbility(OBJECT)
- FeatureAbility.startAbilityForResult(OBJECT)
三.資源管理
JS UI框架下的資源管理目錄如下:

圖19 JS UI下資源目錄結(jié)構(gòu)
● app.js文件用于全局JavaScript邏輯和應用生命周期管理。
● pages目錄用于存放所有組件頁面。
● common目錄用于存放公共資源文件,比如:媒體資源,自定義組件和JS文件。
● resources目錄用于存放資源配置文件,比如:全局樣式、多分辨率加載等配置文件。
● i18n目錄用于配置不同語言場景資源內(nèi)容,比如:應用文本詞條,圖片路徑等資源。資源文件命名為“語言地區(qū).json”格式。
其中,
● .hml結(jié)尾的HML模板文件,這個文件用來描述當前頁面的文件布局結(jié)構(gòu)。
● .css結(jié)尾的CSS樣式文件,這個文件用于描述頁面樣式。
● .js結(jié)尾的JS文件,這個文件用于處理頁面和用戶的交互。
資源引用:

❖ t方法引用資源,t方法引用資源,t既可以在hml中使用,也可以在js中使用,$t參數(shù)說明如下:

示例代碼如下:
• enUS.json中定義:
- {
- "strings": {
- "hello": "Hello world!",
- ……
- },
- }
• HML中引用:
- <div>
- <!-- text中顯示“Hello world!” -->
- <text>{{ $t('strings.hello') }}</text>
- </div>
• JS中引用:
- export default {
- data: {
- hello: '',
- },
- onInit() {
- this.hello = this.$t('strings.hello');
- },
- }
❖ 單復數(shù)通過tc引用資源,定義單復數(shù)資源的內(nèi)容通過json格式的key為“zero”、“one”、“two”、“few”、“many”和“other”區(qū)分,tc引用資源,定義單復數(shù)資源的內(nèi)容通過json格式的key為“zero”、“one”、“two”、“few”、“many”和“other”區(qū)分,tc參數(shù)說明如下:

示例代碼例如下:
• enUS.json中定義:
- {
- "strings": {
- "people": {
- "one": "one person",
- "other": "{count} people"
- }
- }
- }
• HML中引用:
- <div>
- <!-- 傳遞數(shù)值為2時:"2 people" 阿拉伯語中此處匹配key為two的詞條-->
- <text>{{ $tc('strings.people', 2) }}</text>
- </div>
• JS中引用:
- export default {
- data: {
- people: '',
- },
- onInit() {
- this. people = this.$tc('strings.people', 2);
- },
- }
❖ r方法引用資源,r方法引用資源,r既可以在hml中使用,也可以在js中使用,$r參數(shù)說明如下:

示例代碼如下:
• resldpi.json中定義:
- {
- "image": {
- "wearable": "common/wearable.png",
- ……
- }
- }
• HML中引用:
- <div>
- <!-- 通過$r來設置對應圖片資源在json配置文件中的path -->
- <image src="{{ $r('image.wearable') }}" class="image"></image>
- </div>
• JS中引用:
- export default {
- private: {
- wearable: '',
- },
- onInit() {
- // 資源格式化:
- this. wearable= this.$r('image. wearable');
- },
- }
最后,本文描述的HarmonyOS應用UI開發(fā)方法可以覆蓋大部分簡單業(yè)務,開發(fā)者可以根據(jù)需求自由選擇JS或者JAVA框架來完成。
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)