DevEcoStudio 个人记录备份 1
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?DevEcoStudio?個人記錄備份 1? ? ? ??
部分轉載自HarmonyOS技術社區,初學者-Study? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
2020年9月10日,HarmonyOS 2.0的發布對于IT界來說又是一件翹首以盼的大事。發布會上,華為消費者業務軟件部總裁王成錄為開發者帶來了一個全面升級的華為鴻蒙版本,各方面能力的大幅提升,完整的應用開發生態,超級終端的全場景生態,即將開啟移動生態的下一下新紀元。
?在參加完鴻蒙2.0的發布會后,又周轉于9月11日華為聯合南北向業務合作伙伴以及應用生態合作伙伴共同主持的各技術分論壇活動。作為一名從事移動應用相關產業近十余年的工作者,自然是對華為鴻蒙2.0提供的完整的應用開發生態更為感興趣。
?《從零開始開發HarmonyOS應用》是華為展示的第一個鴻蒙應用示例,示例簡單的介紹了多設備自適應布局、輸入事件處理、和跨設備流轉。
1 創建應用工程
使用 DevEco Studio 創建應用工程,在菜單欄打開“File>New>New Project”,在彈出的對話框中選擇java工程模板
選擇好模板之后點擊“Next”,在下一個界面中指定“Project Name”和“Package Name”,然后點擊“Finish”即可建立工程
一個建立好的工程包含以下目錄
2 設計用戶界面
在Java UI框架中,提供了兩種編寫布局的方式:在XML中聲明UI布局和在代碼中創建布局。這兩種方式創建出的布局沒有本質差別,此例主要通過XML的方式編寫應用的頁面
2.1 XML編寫頁面
2.1.1 新建XML頁面
在“Project”窗口,打開“entry > src > main > resources > base”,右鍵點擊“base”文件夾,選擇“New > Directory”,命名為“layout”。
右鍵點擊“layout”文件夾,選擇“New > File”命名為“main_layout.xml”。
在“layout”文件夾下可以看到新增了“main_layout.xml”文件。
2.1.2 編寫XML代碼
這個示例中自適應布局的實現,主要是基于AdaptiveBoxLayout新的布局樣式,它可以將布局在橫豎屏設備上進行自適應分布排列。開發者可以將布局代碼寫在“main_layout.xml”文件,關于布局代碼怎樣實現可以參考文檔中心
如果布局中引用到圖片資源,需要將圖片放到 “resources>base>media”
2.2加載XML布局
在“Project”窗口中,選擇“entry > src > main > java > com.huawei.example.helloworld > slice”,打開“MainAbilitySlice.java”文件。重寫onStart()方法加載XML布局,示例代碼如下:
1.package com.huawei.example.helloworld.slice; 2.import com.huawei.example.helloworld.ResourceTable; 3.import ohos.aafwk.ability.AbilitySlice; 4.import ohos.aafwk.content.Intent; 5. 6.public class MainAbilitySlice extends AbilitySlice { 7. 8. @Override 9. public void onStart(Intent intent) { 10. super.onStart(intent); 11. super.setUIContent(ResourceTable.Layout_main_layout); // 加載XML布局 12. } 13. 14. @Override 15. public void onActive() { 16. super.onActive(); 17. } 18. 19. @Override 20. public void onForeground(Intent intent) { 21. super.onForeground(intent); 22. } 23.}應用運行效果如圖所示:
2.3基礎UI組件解釋
創建xml的時候默認的是DirectionalLayout,這個布局表用于單一方向排列,你可以理解為AS的線性布局,還有五種布局分別是什么呢? AdaptiveBoxLayout(自適應盒式布局) DependentLayout(相關布局,你可以理解為是AS的相對布局) PositionLayout(位置布局,相當于絕對布局) StackLayout(堆疊布局) TableLayout(表格布局)3 輸入事件處理
輸入事件包括兩種,一種是觸控事件,一種是按鍵事件。
3.1 觸控事件
組件的一個重要作用是當用戶點擊組件時,會執行相應的操作或者界面出現相應的變化。用戶點擊組件時,組件對象將收到一個點擊事件。開發者可以自定義響應點擊事件的方法。例如,通過創建一個Component.ClickedListener對象,然后通過調用setClickedListener將其分配給組件。示例代碼如下
1. //1.先導入ohos.agp.components.Image 2. //2.從定義的xml中獲取Image對象 3. Image remote = (Image) findComponentById(ResourceTable.Id_remote); 4. //3.為Image設置點擊事件回調 5. remote.setClickedListener(component -> { 6. //4.此處添加點擊按鈕后的事件處理邏輯 7. migrateAbility(); 8. });?3.2 按鍵點擊事件
當設備按鍵按下時,相應的Ability對象將收到一個KeyEvent事件。開發者可以自定義響應點擊事件的方法
一個示例代碼如下
1.public boolean onKeyEvent(Component component, KeyEvent keyEvent) { 2. if (keyEvent.isKeyDown() 3. && keyEvent.getKeyCode() == KeyEvent.KEY_DPAD_CENTER 4. && component.getId() == ResourceTable.Id_remote) { 5. continueAbility(); 6. return true; 7. } 8. return false; 9.}4 跨設備流轉
4.1 申請權限
權限即系統用于控制第三方應用或服務訪問用戶敏感個人數據或操作敏感能力的授權方式,當第三方應用或服務嘗試訪問用戶個人數據或操作敏感能力時,系統通過彈窗的形式請求用戶授權。用戶可授權此應用使用相關權限,后續也可取消此授權。例如打車類應用為了定位,在獲取用戶的地理位置信息前需向用戶申請,用戶同意此應用使用,后續也可取消此授權。
當使用“流轉”功能需要申請遷移權限DISTRIBUTED_DATASYNC
4.1.1 在config.json中聲明權限
1. "reqPermissions": [ 2. { 3. "name": "ohos.permission.DISTRIBUTED_DATASYNC" 4. } 5. ]4.1.2 在MainAbilitySlice.java中請求權限
1.private void migrateAbility() { 2. if (verifySelfPermission(SystemPermission.DISTRIBUTED_DATASYNC) 3. == IBundleManager.PERMISSION_GRANTED) { 4. this.continueAbility(); 5. } else { 6. requestPermission(SystemPermission.DISTRIBUTED_DATASYNC); 7. } 8.}4.2 跨設備流轉
僅continueAbility一行代碼即可完成應用在設備之間流轉,依托的還是鴻蒙OS的分布式軟總線、分布式數據庫的能力。在此基礎上將這些能力通過接口的形式提供開發者。
事實上流轉并非“一行代碼可以完成”,如果開發者想在流轉過程中做更多的事情,那么可以通過IAbilifyContinuation接口中的方法進行實現。
IAbilityContinuation接口方法說明如下
| 接口名稱 | 說明 |
| onStartContinuation | Page請求遷移后,系統首先回調此方法,開發者可以在此回調中決策當前是否可以執行遷移,比如,彈框讓用戶確認是否開始遷移。 |
| onSaveData | 如果onStartContinuation()返回true,則系統回調此方法,開發者在此回調中保存必須傳遞到另外設備上以便恢復Page狀態的數據。 |
| onRestoreData | 源側設備上Page完成保存數據后,系統在目標側設備上回調此方法,開發者在此回調中接受用于恢復Page狀態的數據。注意,在目標側設備上的Page會重新啟動其生命周期,無論其啟動模式如何配置。且系統回調此方法的時機在onStart()之前。 |
| onCompleteContinuation | 目標側設備上恢復數據一旦完成,系統就會在源側設備上回調Page的此方法,以便通知應用遷移流程已結束。開發者可以在此檢查遷移結果是否成功,并在此處理遷移結束的動作,例如,應用可以在遷移完成后終止自身生命周期。 |
Ability以及AbilitySlice都需要實現IAbilityContinuation接口,并實現其中的方法。示例代碼如下
1. @Override 2. public boolean onStartContinuation() { 3. return true; 4. } 5. 6. @Override 7. public boolean onSaveData(IntentParams intentParams) { 8. return true; 9. } 10. 11. @Override 12. public boolean onRestoreData(IntentParams intentParams) { 13. return true; 14. } 15. 16. @Override 17. public void onCompleteContinuation(int i) { 18. 19. }?首先來看一張圖,很普通,我相信每一個人一開始新建使用Java語言的鴻蒙項目都是這樣的目錄結構,前面我們說到HUAWEI DevEco Studio是基于IntelliJ IDEA Community開源版本所打造出來的。那么它就會跟IDEA 和Android Studio 會有點像,那么同樣的項目結構也比較像,同樣的我在AS中也新建了一個項目,下面是對比圖。
打開我之前創建的鴻蒙HelloWorld項目
左邊的是DS,右邊是AS。基本上差不太多,但是還有點點差點,下面說一下
DS的主模塊是entry,AS的主模塊是app,對于功能中兩個build.gradle的功能是類似的,entry/app下面的build.gradle對當前模塊進行控制,而工程根目錄下的工程級build.gradle用于工程的全局設置。其中我們對AS中AndroidManifest.xml是很熟悉的,但是對于DS中用了另一種文件,那就是config.json,這是一個應用清單文件,用于描述應用的全局配置信息、在具體設備上的配置信息和HAP的配置信息。它的地位就相當于AS中的AndroidManifest.xml。
打開這個文件來看看里面有什么內容:截圖截不全,所以我就直接把里面的代碼貼出來了:
1. config.json (配置文件)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | { ?"app": { ??"bundleName": "com.llw.helloworld", ??"vendor": "llw", ??"version": { ???"code": 1, ???"name": "1.0" ??}, ??"apiVersion": { ???"compatible": 3, ???"target": 3 ??} ?}, ?"deviceConfig": {}, ?"module": { ??"package": "com.llw.helloworld", ??"name": ".HelloWorld", ??"reqCapabilities": [ ???"video_support" ??], ??"deviceType": [ ???"wearable" ??], ??"distro": { ???"deliveryWithInstall": true, ???"moduleName": "entry", ???"moduleType": "entry" ??}, ??"abilities": [ ???{ ????"skills": [ ?????{ ??????"entities": [ ???????"entity.system.home" ??????], ??????"actions": [ ???????"action.system.home" ??????] ?????} ????], ????"orientation": "landscape", ????"formEnabled": false, ????"name": "com.llw.helloworld.MainAbility", ????"icon": "$media:icon", ????"description": "$string:mainability_description", ????"label": "HelloWorld", ????"type": "page", ????"launchType": "standard" ???} ??] ?} } |
它的數據結構是JSON格式的,這和我們平時通過接口請求返回的數據比較的類,然后收縮一下,就比較清晰了。
可以看到主要的分為三個部分:app、deviceConfig、module,你可以理解為三個對象。
①?app?表示應用的全局配置信息。同一個應用的不同HAP包的“app”配置必須保持一致。(簡單說就是你所有模塊里面的config.json中的app對象都要一模一樣)
②?deviceConfig?表示應用在具體設備上的配置信息。(目前的設備有TV、智能手表、運動手表)
③?module?表示HAP包的配置信息。該標簽下的配置只對當前HAP包生效。(簡單說就是你當前模塊的配置信息)
是不是覺得清晰了那么一丟丟,好繼續往里面看,下面我們展開這個app對象,看一下里面可以配置哪些屬性。
下面也是一個個說明:
- bundleName?表示應用的包名,用于標識應用的唯一性。采用反域名形式的字符串表示(例如,com.llw.helloworld)。建議第一級為域名后綴“com”,第二級為廠商/個人名,第三級為應用名,也可以采用多級。支持的字符串長度為7~127字節。不可省缺。
- vendor?表示對應用開發廠商的描述。字符串長度不超過255字節。可以省缺,省缺值為空。
- version?這是一個對象,表示應用的版本信息。它里面有兩個參數,code和name,code?表示應用的版本號,僅用于HarmonyOS管理該應用,對用戶不可見。取值為大于零的整數。name表示應用的版本號,用于向用戶呈現。取值可以自定義。兩個參數都不可省缺。
- apiVersion?這也是一個對象,表示應用依賴的HarmonyOS的API版本。它里面也有兩個參數,compatible?和?target?,compatible?表示應用運行需要的API最小版本。取值為大于零的整數。不可省缺target?表示應用運行需要的API目標版本。取值為大于零的整數。可缺省,缺省值為應用所在設備的當前API版本。
app對象就說完了,下面說deviceConfig。
??從圖片上來看,里面是個空的,空的你說個錘子啊!冷靜、冷靜,現在是空的不代表以后就是空的,其實它是由參數的,這個需要看官網上的文檔了。
??介紹是這樣的deviceConfig包含在具體設備上的應用配置信息,可以包含default、car、tv、wearable、liteWearable、smartVision等屬性。default標簽內的配置是適用于所有設備通用,其他設備類型如果有特殊的需求,則需要在該設備類型的標簽下進行配置。雖然它目前支持的模擬設備只有tv、wearable、liteWearable,但是具體的設備還有一些其他的。下面也來介紹一下,先來看一下里面的內容有哪些
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | "deviceConfig": { ??"default": { ???"process": "com.llw.helloworld.hiworld", ???"directLaunch": false, ???"supportBackup": false, ???"network": { ????"usesCleartext": true, ????"securityConfig": { ?????"domainSettings": { ??????"cleartextPermitted": true, ??????"domains": [ ???????{ ????????"subDomains": true, ????????"name": "example.ohos.com" ???????} ??????] ?????} ????} ???} ??} ?} |
然后收縮一下,如下:
之前提到deviceConfig中有default、car、tv、wearable、liteWearable、smartVision。這六個對象,但是圖片上只有一個,你仿佛你在騙我!我翻譯一下
default代表的就是所有設備,而其他的五個,和這個default對象里面的內容時一模一樣的,只是名字不一樣,比如你把這個default改成car,那就是對應汽車的設備配置,改成tv就是對應電視的設備配置。比如:
所以自由度很高,可以根據自己的實際需求,你想怎么玩就怎么玩。下面講一下里面具體的對象屬性:
- process 表示應用或者Ability的進程名。如果在“deviceConfig”標簽下配置了“process”標簽,則該應用的所有Ability都運行在這個進程中。 如果在“abilities”標簽下也為某個Ability配置了“process”標簽,則該Ability就運行在這個進程中。該標簽僅適用于智慧屏、智能穿戴、車機。可缺省,缺省為應用的軟件包名。
- directLaunch 表示應用是否支持在設備未解鎖狀態直接啟動。如果配置為“true”,則表示應用支持在設備未解鎖狀態下啟動。使用場景舉例:應用支持在設備未解鎖情況下接聽來電。可缺省,缺省為“false”。該標簽僅適用于智慧屏、智能穿戴、車機。
- supportBackup 表示應用是否支持備份和恢復。如果配置為“false”,則不支持為該應用執行備份或恢復操作。該標簽僅適用于智慧屏、智能穿戴、車機。可缺省,缺省為“false”。
- compressNativeLibs 表示libs庫是否以壓縮存儲的方式打包到HAP包。如果配置為“false”,則libs庫以不壓縮的方式存儲,HAP包在安裝時無需解壓libs,運行時會直接從HAP內加載libs庫。該標簽僅適用于智慧屏、智能穿戴、車機。可缺省,缺省為“true”。
- network 表示網絡安全性配置。該標簽允許應用通過配置文件的安全聲明來自定義其網絡安全,無需修改應用代碼。
先看看network里面有什么
- usesCleartext?表示是否允許應用使用明文網絡流量(例如,明文HTTP)。true:允許應用使用明文流量的請求。false:拒絕應用使用明文流量的請求。可缺省,缺省為“false”。
- securityConfig?表示應用的網絡安全配置信息。可缺省,缺省為空。
然后再展開securityConfig,如下
- domainSettings?表示自定義的網域范圍的安全配置,支持多層嵌套,即一個domainSettings對象中允許嵌套更小網域范圍的domainSettings對象。可缺省,缺省為空。它里面有cleartextPermitted屬性和domains對象。
- cleartextPermitted表示自定義的網域范圍內是否允許明文流量傳輸。當useCleartext和securityConfig同時存在時,自定義網域是否允許明文流量傳輸以cleartextPermitted的取值為準。true:允許明文流量傳輸。false:拒絕明文流量傳輸。不可省缺。
- domains?表示域名配置信息,包含兩個參數:subDomains和name。subDomains(布爾類型):表示是否包含子域名。如果為 “true”,此網域規則將與相應網域及所有子網域(包括子網域的子網域)匹配。否則,該規則僅適用于精確匹配項。
- name(字符串):表示域名名稱。不可省缺。
說是說deviceConfig里面沒有東西,但是這么一頓操作下來,我人都傻了。好了,清醒一點,還有一個module沒說呢?
下面來看module對象的內部結構。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | "module": { ??"package": "com.llw.helloworld", ??"name": ".HelloWorld", ??"reqCapabilities": [ ???"video_support" ??], ??"deviceType": [ ???"wearable" ??], ??"distro": { ???"deliveryWithInstall": true, ???"moduleName": "entry", ???"moduleType": "entry" ??}, ??"abilities": [ ???{ ????"skills": [ ?????{ ??????"entities": [ ???????"entity.system.home" ??????], ??????"actions": [ ???????"action.system.home" ??????] ?????} ????], ????"orientation": "landscape", ????"formEnabled": false, ????"name": "com.llw.helloworld.MainAbility", ????"icon": "$media:icon", ????"description": "$string:mainability_description", ????"label": "HelloWorld", ????"type": "page", ????"launchType": "standard" ???} ??] ?} |
媽耶,這個module里面的東西比app和deviceConfig兩個對象里面加起來還要多。(555555~ 我不想學鴻蒙了,我放棄了,現在下車還來得及嗎?別想了,車門我已經焊死了,雅蠛蝶!!!)
收縮一下,這么一看好像內容也不是很多,對吧!畫外音:對個屁!
- package?表示HAP的包結構名稱,在應用內應保證唯一性。采用反向域名格式(建議與HAP的工程目錄保持一致)。字符串長度不超過127字節。該標簽僅適用于智慧屏、智能穿戴、車機。不可省缺。
- name?表示HAP的類名。采用反向域名方式表示,前綴需要與同級的package標簽指定的包名一致,也可采用“.”開頭的命名方式。字符串長度不超過255字節。該標簽僅適用于智慧屏、智能穿戴、車機。不可省缺。
- reqCapabilities?表示需要的技術支持,這是一個字符串數組,里面可以看到有一個video_support,表示視頻支持。
- deviceType?表示允許Ability運行的設備類型。系統預定義的設備類型包括:tv(智慧屏)、car(車機)、wearable(智能穿戴)、liteWearable(輕量級智能穿戴)等。不可省缺。
distro?表示HAP發布的具體描述。這是一個對象,該標簽僅適用于智慧屏、智能穿戴、車機。不可省缺。它里面還有
- deliveryWithInstall?表示當前HAP是否支持隨應用安裝。true:支持隨應用安裝。false:不支持隨應用安裝。不可省缺。
- moduleName?表示當前HAP的名稱。不可省缺。
- moduleType?表示當前HAP的類型,包括兩種類型:entry和feature。不可省缺。
abilities?表示當前模塊內的所有Ability。采用對象數組格式,其中每個元素表示一個Ability對象。可缺省,缺省值為空。下面來看看里面有哪些屬性
可以看到這個里面有一個對象數組skills,其余就是就是一些配置的屬性了。skills?里面還有兩個字符串數組entities和actiions,下面先從這個skills?來分析。
skills?打過游戲的都知道,這是技能的意思。不過在這里是表示Ability能夠接收的Intent的特征。 這個Intent的用法其實和Android里面是比較像的,比如我們跳轉到手機的短信頁面就可以通過Intent,還有打電話也可以通過Intent,類似這樣的特征。可缺省,缺省值為空。從上圖我們知道里面還有兩個字符串對象。
- actions?表示能夠接收的Intent的action值,可以包含一個或多個action。取值通常為系統預定義的action值,可缺省,缺省值為空。
- entities?表示能夠接收的Intent的Ability的類別(如視頻、桌面應用等),可以包含一個或多個entity。取值通常為系統預定義的類別,可缺省,缺省值為空。
看到這里你會很奇怪,因為你知道Android里面除了有Intent幫我們實現之外還有Uri可以實現,那么上面的截圖中也沒有這個屬性,是為什么?答案就是這個屬性屬于開發者自行去做配置。這里就補充一下這個屬性,它其實一個對象數組。它就是uris
uris?表示能夠接收的Intent的uri,可以包含一個或者多個uri。可缺省,缺省值為空。它里面的數據如下:
| 1 2 3 4 5 6 7 8 9 | "uris": [ ??????{ ?????????"scheme": "http", ?????????"host": "www.hefeng.com", ?????????"port": "8080", ?????????"path": "query/goodweather/today", ?????????"type": "text" ???????} ?????] |
??里面的對象屬性值就是字面意思,都是可以省缺的,省缺值為空。你可以根據不同的Uri配置不同的對象,都放到這個對象數組里面就可以了。下面看abilities中的其他屬性。
orientation?表示該Ability的顯示模式。該標簽僅適用于page類型的Ability。取值范圍如下:unspecified:由系統自動判斷顯示方向。landscape:橫屏模式。portrait:豎屏模式。followRecent:跟隨棧中最近的應用。可缺省,缺省值為“unspecified”。
formEnabled?表示FA類型的Ability是否提供卡片(form)能力。該標簽僅適用于page類型的Ability。true:提供卡片能力。false:不提供卡片能力。可缺省,缺省值為“false”。
name?表示Ability名稱。取值可采用反向域名方式表示,由包名和類名組成,如“com.llw.helloworld.MainAbility”;也可采用“.”開頭的類名方式表示,如“.MainAbility”。該標簽僅適用于智慧屏、智能穿戴、車機。不可省缺。
icon?表示Ability圖標資源文件的索引。取值示例:$media:ability_icon。如果在該Ability的“skills”屬性中,“actions”的取值包含 “action.system.home”,“entities”取值中包含“entity.system.home”,則該Ability的icon將同時作為應用的icon。如果存在多個符合條件的Ability,則取位置靠前的Ability的icon作為應用的icon。可缺省,缺省值為空。
description?表示對Ability的描述。取值可以是描述性內容,也可以是對描述性內容的資源索引,以支持多語言。可缺省,缺省值為空。
label?表示Ability對用戶顯示的名稱。取值可以是Ability名稱,也可以是對該名稱的資源索引,以支持多語言。如果在該Ability的“skills”屬性中,“actions”的取值包含 “action.system.home”,“entities”取值中包含“entity.system.home”,則該Ability的label將同時作為應用的label。如果存在多個符合條件的Ability,則取位置靠前的Ability的label作為應用的label。可缺省,缺省值為空。
type?表示Ability的類型。取值范圍如下:page:表示基于Page模板開發的FA,用于提供與用戶交互的能力。service:表示基于Service模板開發的PA,用于提供后臺運行任務的能力。data:表示基于Data模板開發的PA,用于對外部提供統一的數據訪問抽象。不可省缺。
launchType?表示Ability的啟動模式,支持“standard”和“singleton”兩種模式:standard:表示該Ability可以有多實例。“standard”模式適用于大多數應用場景。singleton:表示該Ability只可以有一個實例。例如,具有全局唯一性的呼叫來電界面即采用“singleton”模式。該標簽僅適用于智慧屏、智能穿戴、車機。可缺省,缺省值為“standard”。
至此,這個config.json的基本信息我們就都知道了,不得不說看起來比AS 的AndroidManifest.xml要復雜一些,看得我是頭皮發麻。可能用的熟悉了就好了。你說呢?
2. entry (應用的主模塊)
應用的主模塊,類似與AS的app模塊,一個APP中,對于同一設備類型必須有且只有一個entry類型的HAP,可獨立安裝運行。它里面的內容如下:
從圖片上來看是和AS的app里面的內容差不多,那就來看看不同的地方在哪里。
首先當然是資源文件夾resources,其實和AS的res是差不多的,只不過DS這里用了全拼。(AS指Android Studio,DS 指DevEco Studio),展開resources如下:
可以看到有兩個文件夾,
base和rawfile,首先從單詞的字面意思來看是基礎和原始文件。官方的意思是 base目錄和 限定詞目錄。按照兩級目錄形式來組織,目錄命名必須符合規范,以便根據設備狀態去匹配相應目錄下的資源文件。聽起來是不是云里霧里,我都不知道你在說啥,下面我說一下我的個人理解,你可以把這個文件夾理解為AS的values文件下,我們之前一些樣式、顏色、尺寸、文字都是放在里面的,基本上一個values就夠了,但是如果要做國際化或者多語言的話,我們會新建一個values-en的文件夾,這個里面的的資源文件就是切換語言之后使用的。那么你就可以把這個限定詞目錄理解為values-en。當然我也不知道對不對啊,先這么理解再說吧。限定詞目錄可以由一個或多個表征應用場景或設備特征的限定詞組合而成,包括語言、文字、國家或地區、橫豎屏、設備類型和屏幕密度等六個維度,限定詞之間通過下劃線(_)或者中劃線(-)連接。開發者在創建限定詞目錄時,需要掌握限定詞目錄的命名要求以及與限定詞目錄與設備狀態的匹配規則。當然這個限定詞還是有命名規范的。
限定詞目錄的命名要求
限定詞的組合順序:語言_文字_國家或地區-橫豎屏-設備類型-屏幕密度。開發者可以根據應用的使用場景和設備特征,選擇其中的一類或幾類限定詞組成目錄名稱。
限定詞的連接方式:語言、文字、國家或地區之間采用下劃線(_)連接,除此之外的其他限定詞之間均采用中劃線(-)連接。例如:zh_Hant_CN、zh_CN-car-ldpi。
限定詞的取值范圍:每類限定詞的取值必須符合表2中的條件,否則,將無法匹配目錄中的資源文件。
?表2?限定詞取值要求
| 語言 | 表示設備使用的語言類型,由2個小寫字母組成。例如:zh表示中文,en表示英語。 詳細取值范圍,參見ISO 639-1(ISO制定的語言編碼標準)。 |
| 文字 | 表示設備使用的文字類型,由1個大寫字母(首字母)和3個小寫字母組成。例如:Hans表示簡體中文,Hant表示繁體中文。 詳細取值范圍,參見ISO 15924(ISO制定的文字編碼標準)。 |
| 國家或地區 | 表示用戶所在的國家或地區,由2~3個大寫字母或者3個數字組成。例如:CN表示中國,GB表示英國。 詳細取值范圍,參見ISO 3166-1(ISO制定的國家和地區編碼標準)。 |
| 橫豎屏 | 表示設備的屏幕方向,取值如下:
|
| 設備類型 | 表示設備的類型,取值如下:
|
| 屏幕密度 | 表示設備的屏幕密度(單位為dpi),取值如下:
|
資源組目錄
base目錄與限定詞目錄下面可以創建資源組目錄(包括element、media、animation、layout、graphic、profile),用于存放特定類型的資源文件
表3?資源組目錄?說明
| element | 表示元素資源,以下每一類數據都采用相應的JSON文件來表征。
| element目錄中的文件名稱建議與下面的文件名保持一致。每個文件中只能包含同一類型的數據。
|
| media | 表示媒體資源,包括圖片、音頻、視頻等非文本格式的文件。 | 文件名可自定義,例如:icon.png。 |
| animation | 表示動畫資源,采用XML文件格式。 | 文件名可自定義,例如:zoom_in.xml。 |
| layout | 表示布局資源,采用XML文件格式。 | 文件名可自定義,例如:home_layout.xml。 |
| graphic | 表示可繪制資源,采用XML文件格式。 | 文件名可自定義,例如:notifications_dark.xml。 |
| profile | 表示其他類型文件,以原始文件形式保存。 | 文件名可自定義。 |
rawfile?這個文件是干嘛的呢?支持創建多層子目錄,目錄名稱可以自定義,文件夾內可以自由放置各類資源文件。rawfile目錄的文件不會根據設備狀態去匹配不同的資源。這個里面就是一個綜合體,相當于包含了AS的drawable和mipmap以及其他的一些文件,只不過它沒有做尺寸上的細分,需要開發者自行細分做不同設備的適配,不過既然是華為里面的東西,我相信到時候會有一個系統的關于這方面的講解的。
系統資源文件
系統資源文件說明
| ic_app | 表示HarmonyOS應用的默認圖標。 | 媒體 |
| request_location_reminder_title | 表示“請求使用設備定位功能”的提示標題。 | 字符串 |
| request_location_reminder_content | 表示“請求使用設備定位功能”的提示內容,即:請在下拉快捷欄打開"位置信息"開關。 | 字符串 |
二、編寫頁面
右鍵點擊“base”文件夾,選擇“New > Directory”,命名為“layout”。
點擊OK,然后右鍵點擊“layout”文件夾,選擇“New >Layout Resources File”,命名為“main_layout.xml”。
單擊Finish,完成布局創建。
布局如下:
| 1 2 3 4 5 6 7 | <?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"> ??? </DirectionalLayout> |
這都是什么鬼東西,我咋看不懂呢?你可能會問ohos是個啥?我就這么告訴你,你把它當成AS中布局文件中的android就可以了。ohos我估計是鴻蒙系統對于布局的一個屬性標識。除了這個,還有DirectionalLayout是什么布局呢?這位朋友你的問題咋這么多呢?嗯?
DirectionalLayout是方向布局,聞所未聞?那么還有沒有其他的一些布局呢?當然有,如下圖所示:
我們創建xml的時候默認的是DirectionalLayout,這個布局表用于單一方向排列,你可以理解為AS的線性布局,還有五種布局分別是什么呢?AdaptiveBoxLayout(自適應盒式布局)、DependentLayout(相關布局,你可以理解為是AS的相對布局)、PositionLayout(位置布局,相當于絕對布局)、StackLayout(堆疊布局)、TableLayout(表格布局)。
好了,上面看你裝逼是裝完了,會用嗎?這個問題問得好,不是全會!哎,先別動手,放下手中的刀,作為剛學的哪能都會啊,而且我現在只是簡單的講解一下,到時候具體的使用肯定也是要大費周章才能講完,這個解釋怎么樣?講真的,你信我,只要我都會使用之后,我絕對會另寫一篇文章來單獨講這個布局,好不好?回到剛才的布局頁面。修改一下后如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?xml version="1.0" encoding="utf-8"?> <DependentLayout ????xmlns:ohos="http://schemas.huawei.com/res/ohos" ????ohos:width="match_parent" ????ohos:height="match_parent" ????ohos:background_element="#000000"> ??<Text ??????ohos:id="$+id:text" ??????ohos:width="match_content" ??????ohos:height="match_content" ??????ohos:center_in_parent="true" ??????ohos:text="Hello World" ??????ohos:text_color="white" ??????ohos:text_size="32fp"/> ??<Button ??????ohos:id="$+id:button" ??????ohos:width="match_content" ??????ohos:height="match_content" ??????ohos:text_size="19fp" ??????ohos:text="Next" ??????ohos:top_padding="8vp" ??????ohos:bottom_padding="8vp" ??????ohos:right_padding="80vp" ??????ohos:left_padding="80vp" ??????ohos:text_color="white" ??????ohos:background_element="$graphic:button_element" ??????ohos:center_in_parent="true" ??????ohos:align_parent_bottom="true"/> </DependentLayout> |
可以看到,我把DirectionalLayout改成DependentLayout之后再里面放了一個Text和一個Button,
首先來看我們不熟悉的屬性值:
| 1 2 | ohos:width="match_content" ohos:height="match_content" |
寬高為match_content,表示組件大小與它的內容占據的大小范圍相適應,簡單說,就是自適應大小,類似于AS的wrap_content,這么一說就好理解了。
| 1 | ohos:center_in_parent="true" |
這個從字面意思看是在父布局內居中的意思。
| 1 | ohos:text_size="32fp" |
文字大小使用fp,尺寸大小使用vp
| 1 | ohos:background_element="$graphic:button_element" |
背景,里面的值通過引用“button_element”來顯示的,你可能會奇怪,為什么要加一個element,單獨用background不行嗎?你別忘了,開發語言是支持JS的,所以你知道為啥有一個element了嗎?
可以看到它引用graphic下面的button_element,沒有就來創建一個,需要在“base”目錄下創建“graphic”文件夾,在“graphic”文件夾中新建一個“button_element.xml”文件。
代碼如下:
| 1 2 3 4 5 6 7 | <?xml version="1.0" encoding="utf-8"?> <shape ????xmlns:ohos="http://schemas.huawei.com/res/ohos" ????ohos:shape="oval"> ??<solid ??????ohos:color="#007DFF"/> </shape> |
那么布局就已經寫好了。下面打開MainAbilitySlice.java
里面的代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package com.llw.helloworld.slice; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.components.DirectionalLayout; import ohos.agp.components.DirectionalLayout.LayoutConfig; import ohos.agp.components.Text; import ohos.agp.colors.RgbColor; import ohos.agp.components.element.ShapeElement; import ohos.agp.utils.Color; import ohos.agp.utils.TextAlignment; public class MainAbilitySlice extends AbilitySlice { ??private DirectionalLayout myLayout = new DirectionalLayout(this); ??@Override ??public void onStart(Intent intent) { ????super.onStart(intent); ????LayoutConfig config = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_PARENT); ????myLayout.setLayoutConfig(config); ????ShapeElement element = new ShapeElement(); ????element.setRgbColor(new RgbColor(255, 255, 255)); ????myLayout.setBackground(element); ????Text text = new Text(this); ????text.setLayoutConfig(config); ????text.setText("Hello World"); ????text.setTextColor(new Color(0xFF000000)); ????text.setTextSize(50); ????text.setTextAlignment(TextAlignment.CENTER); ????myLayout.addComponent(text); ????super.setUIContent(myLayout); ??} ??@Override ??public void onActive() { ????super.onActive(); ??} ??@Override ??public void onForeground(Intent intent) { ????super.onForeground(intent); ??} } |
只要看里面的onStart方法里面的代碼,因為我們一開始運行項目就會有一個Hello World!但是之前里面沒有布局啊,所以默認的項目是在代碼中創建布局的,
下面來看看這個代碼的意思,注釋已經寫在里面了
下面清理掉onStart中的方法,增加
| 1 | super.setUIContent(ResourceTable.Layout_main_layout); // 加載XML布局 |
添加我們剛才創建的布局。然后運行到遠程模擬器上面,這個確實也比較煩就是需要登錄才能行。運行出來的效果如下:
三、頁面跳轉
APP只有一個頁面可不行啊,下面來新建一個頁面。
1. 創建Feature Ability
右鍵點擊“com.example.myapplication”文件夾,選擇“New > Ability > Empty Feature Ability(Java)”。
改一下Ability的名字
點擊finish,然后你打開這個SecondAbilitySlice.java之后你會發現里面的代碼也幫你生成好了,也是Hello World。首先把它的待刪掉。
刪除之后,如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.llw.helloworld.slice; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; public class SecondAbilitySlice extends AbilitySlice { ??@Override ??protected void onStart(Intent intent) { ????super.onStart(intent); ??} ??@Override ??protected void onActive() { ????super.onActive(); ??} ??@Override ??protected void onForeground(Intent intent) { ????super.onForeground(intent); ??} } |
添加代碼后如下所示:每一行添加的代碼都有注釋:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | package com.llw.helloworld.slice; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.agp.colors.RgbColor; import ohos.agp.components.DependentLayout; import ohos.agp.components.Text; import ohos.agp.components.element.ShapeElement; import ohos.agp.utils.Color; import java.math.MathContext; import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT; import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_PARENT; public class SecondAbilitySlice extends AbilitySlice { ??@Override ??protected void onStart(Intent intent) { ????super.onStart(intent); ????/*? 使用代碼設置布局? */ ????//聲明一個相關布局 ????DependentLayout myLayout = new DependentLayout(this); ????//設置布局的大小 寬高占滿屏幕 ????myLayout.setWidth(MATCH_PARENT); ????myLayout.setHeight(MATCH_PARENT); ????//創建一個形狀元素對象 ????ShapeElement element = new ShapeElement(); ????//設置顏色 ????element.setRgbColor(new RgbColor(0,0,0)); ????//設置布局的背景 ????myLayout.setBackground(element); ????//創建一個文本組件 ????Text text = new Text(this); ????//設置文本組件顯示的內容 ????text.setText("How are you?"); ????//設置寬度占滿父布局 ????text.setWidth(MATCH_PARENT); ????//設置文字大小 ????text.setTextSize(55); ????//設置文字顏色 ????text.setTextColor(Color.WHITE); ????//設置文本的布局 寬高自適應 ????DependentLayout.LayoutConfig textConfig = new DependentLayout.LayoutConfig(MATCH_CONTENT,MATCH_CONTENT); ????//添加顯示規則 顯示在布局的中央 ????textConfig.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT); ????//給Text組件設置布局配置 ????text.setLayoutConfig(textConfig); ????//然后把Text組件添加到布局中 ????myLayout.addComponent(text); ????//最后加載布局 ????super.setUIContent(myLayout); ??} ??@Override ??protected void onActive() { ????super.onActive(); ??} ??@Override ??protected void onForeground(Intent intent) { ????super.onForeground(intent); ??} } |
2. 跳轉邏輯
打開第一個頁面的“MainAbilitySlice.java”文件,重寫onStart()方法添加按鈕的響應邏輯,實現點擊按鈕跳轉到下一頁。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | package com.llw.helloworld.slice; import com.llw.helloworld.ResourceTable; import ohos.aafwk.ability.AbilitySlice; import ohos.aafwk.content.Intent; import ohos.aafwk.content.Operation; import ohos.agp.components.Button; import ohos.agp.components.Component; import ohos.agp.components.DirectionalLayout; import ohos.agp.components.DirectionalLayout.LayoutConfig; import ohos.agp.components.Text; import ohos.agp.colors.RgbColor; import ohos.agp.components.element.ShapeElement; import ohos.agp.utils.Color; import ohos.agp.utils.TextAlignment; /** @author llw ?* @noinspection All */ public class MainAbilitySlice extends AbilitySlice { ??@Override ??public void onStart(Intent intent) { ????super.onStart(intent); ????// 加載XML布局 ????super.setUIContent(ResourceTable.Layout_main_layout); ????//這一步就類似與findViewById 初始化組件 ????Button button = (Button) findComponentById(ResourceTable.Id_button); ????if(button != null){ ??????//設置點擊監聽 ??????button.setClickedListener(new Component.ClickedListener() { ????????@Override ????????public void onClick(Component component) { ??????????// 還是通過Intent來跳轉 ??????????Intent secondIntent = new Intent(); ??????????// 指定待啟動FA的bundleName和abilityName ??????????Operation operation = new Intent.OperationBuilder() ??????????????// 設備id ??????????????.withDeviceId("") ??????????????// 應用的包名 怎么跳轉個頁面搞得這么麻煩呢? ??????????????.withBundleName("com.llw.helloworld") ??????????????// 跳轉目標的路徑名 通常是包名+類名 或者 . + 類名 ??????????????.withAbilityName("com.llw.helloworld.SecondAbility") //????????????? .withAbilityName(".SecondAbility") ??????????????.build(); ??????????// 設置操作方式 ??????????secondIntent.setOperation(operation); ??????????// 通過AbilitySlice的startAbility接口實現啟動另一個頁面 ??????????startAbility(secondIntent); ????????} ??????}); ????} ??} ??@Override ??public void onActive() { ????super.onActive(); ??} ??@Override ??public void onForeground(Intent intent) { ????super.onForeground(intent); ??} } |
運行效果如下:用手機拍的,莫要見怪呀。
總結
以上是生活随笔為你收集整理的DevEcoStudio 个人记录备份 1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java-字节流
- 下一篇: 项目管理计划的制定过程