初識(shí)鴻蒙開發(fā)
了解鴻蒙開發(fā)套件
鴻蒙開發(fā)套件由七個(gè)主要組件組成。
- HarmonyOS Design:視覺設(shè)計(jì)。
- ArkTs:項(xiàng)目開發(fā)語(yǔ)言。
- ArkUI:一套UI框架。
- ArkCompiler:AOT優(yōu)化,優(yōu)化字節(jié)碼編譯,提高運(yùn)行效率。
- DevEco Studio:開發(fā)編譯器;IDEA。
- DevEco Testing:面向測(cè)試人員的開發(fā)工具。
- AppGallery Connect:分發(fā)運(yùn)營(yíng)套件,提供了很多的云函數(shù)、云數(shù)據(jù)庫(kù)功能。
整個(gè)鴻蒙應(yīng)用的開發(fā)步驟分為三步:
- 準(zhǔn)備和設(shè)計(jì)。
- 代碼開發(fā)。
- 測(cè)試和上架。
而我們作為開發(fā)人員,主要接觸的是DevEco Studio編譯器、ArkTs開發(fā)語(yǔ)言、ArkUI框架。
DevEco Studio安裝
DevEco 的初始化安裝,主要需要三個(gè)東西:nodejs、OHPM包管理器、HarmonyOS SDK。
鴻蒙的編譯器DevEco Studio,需要使用管理員身份執(zhí)行,不然安裝sdk可能會(huì)失敗。
確保最終是全綠,才可以進(jìn)行下一步的項(xiàng)目創(chuàng)建
踩坑
公司電腦加密系統(tǒng)也會(huì)導(dǎo)致DevEco Studio開發(fā)環(huán)境配置不成功。比如 ohpm卡安裝
解決ohpm卡安裝問題
OpenHarmony Ohpm安裝歷程(個(gè)人踩坑,最后安裝成功)-CSDN博客
配置OHPM代理
設(shè)置Ohpm代理
找到FIle->Settings->Ohpm,點(diǎn)擊Optimize config。
彈出以下彈窗:
ohpm registry:配置ohpm倉(cāng)的地址信息,repo./ohpm/
如果需要設(shè)置網(wǎng)絡(luò)代理,那么可以勾選HTTP proxy并進(jìn)行配置。
關(guān)閉Windows defender
關(guān)閉defender,或者將devEco相關(guān)內(nèi)容添加到排除項(xiàng)
運(yùn)行首個(gè)項(xiàng)目
- 創(chuàng)建項(xiàng)目
創(chuàng)建首個(gè)項(xiàng)目,選擇Create Project->Empty Ability,由此可知Ability等于安卓的Activity。
- 模擬器的配置
(和Android studio其實(shí)差不大多,摸索就行),DevEco Studio支持Remote 云控模擬器,還是很有意思的。
- 運(yùn)行項(xiàng)目
點(diǎn)擊run運(yùn)行,helloworld就有了
了解ArkTS
以前學(xué)習(xí)的HTML網(wǎng)頁(yè)開發(fā),它包含了H5+CSS+JavaScript,從而實(shí)現(xiàn)了一個(gè)完整的網(wǎng)頁(yè)結(jié)構(gòu)。
那么也就意味著如果要掌握網(wǎng)頁(yè)開發(fā),需要同時(shí)掌握HTML語(yǔ)法、CSS語(yǔ)法、JavaScript語(yǔ)法,需要掌握三樣內(nèi)容。
而ArkTS相比起H5來說則更加容易,只需要掌握ArkTS這一門語(yǔ)言就可以完成UI和交互邏輯的開發(fā)工作了。
ArkTS與Typescript
- ArkTS基于Typescript,而Typescript基于JavaScript;Typescript相比較于JavaScript新增了靜態(tài)類型定義功能;所以ArkTS也具有Typescript的這些特性。
- ArkTS可以理解為等同于網(wǎng)頁(yè)的JavaScript。同時(shí),ArkTS又拓展了聲明式UI、狀態(tài)管理等特性。
ArkTS的優(yōu)點(diǎn)
- 開發(fā)效率高、開發(fā)體驗(yàn)好。
- 性能優(yōu)越。
- 有多系統(tǒng)適配,接入能力。
ArkTS雖然使用的是聲明式UI,但是它底層有個(gè)方舟編譯器,方舟編譯器會(huì)幫我們把寫的TS語(yǔ)言編譯成字節(jié)碼,最終轉(zhuǎn)為機(jī)器碼。而且還會(huì)把 字節(jié)碼轉(zhuǎn)換為機(jī)器碼的 動(dòng)作,從運(yùn)行器提前到編譯期,從而大大提高運(yùn)行效率。
以及還有一套UI后端引擎,提供了一套統(tǒng)一的頁(yè)面渲染的指令,這些指令最后提供給渲染總線,最終渲染總線將指令傳遞給了高效渲染引擎;高效渲染引擎會(huì)對(duì)我們的UI指令再進(jìn)行一層的優(yōu)化,大大提高頁(yè)面渲染效率。
同時(shí)鴻蒙系統(tǒng)底層對(duì)ArkTS提供了不同平臺(tái)的適配層和橋接層。
因此,ArkTS開發(fā)的鴻蒙應(yīng)用,不僅簡(jiǎn)單,性能也很好,而且具有跨系統(tǒng)適配能力。
Typescript基礎(chǔ)語(yǔ)法
Typescript演練場(chǎng)
訪問Typescript官網(wǎng),點(diǎn)擊Playground,可以進(jìn)入到Typescript演練場(chǎng)、,在此處可以練習(xí)Typescript語(yǔ)法。
變量聲明
- Typescript在JavaScript的基礎(chǔ)上加入了靜態(tài)類型檢查功能,因此每一個(gè)變量都有固定的數(shù)據(jù)類型。
let msg:string='hello world'//聲明一個(gè)string類型的msg變量。
let:聲明變量的關(guān)鍵幀。也可以使用const,表示常量。
msg:變量名。
string:變量的數(shù)據(jù)類型;Typescript相較于JavaScript就是多了這一部分變量的數(shù)據(jù)類型聲明。
'hello world':賦的值;可以使用單引號(hào)',也可以使用雙引號(hào)""。
數(shù)據(jù)類型
let msg:string='hello world'
-
- 字符串拼接時(shí),通過使用
符號(hào),可以開啟 ${} (單/雙引號(hào)下不支持)。
const anExampleVariable = "Hello World"
console.log(`輸出anExampleVariable=${anExampleVariable}`)
//打印結(jié)果:輸出anExampleVariable=Hello World
- number:數(shù)值類型;不區(qū)分整數(shù)、浮點(diǎn)數(shù),都使用number。
let age:number=18
let finished:boolean=true
let a:any='jack'
a=21;
- union:聯(lián)合類型,可以是多個(gè)指定類型的一種。
//聯(lián)合類型U,可以是string,也可以number、boolean;它們的數(shù)據(jù)類型可以自由切換。
let u:string|number|boolean="union";
u=100;
// 聲明了一個(gè)對(duì)象,類別兩個(gè)變量name,age。它們的值對(duì)應(yīng) name為jack,age為24.
let p={name:'jack',age:24}
//在控制臺(tái)輸出對(duì)象p的name屬性。
console.log(p.name);
console.log(p['name']);
- Array:數(shù)組;內(nèi)部的元素可以是任意類型。
let names:Array<string>=['Jack','Rose']
let ages:number[]=[20,21]
console.log(names[0])
console.log(ages[0].toString())
注意:
- 開發(fā)時(shí)通常是在函數(shù)中會(huì)用到any、union類型。
- 聲明普通變量時(shí),盡可能不使用any。
條件控制
Typescript和大多數(shù)語(yǔ)言類似,都是支持if-else、switch 條件控制語(yǔ)句的。
let num:number=88;
//判斷奇偶數(shù)
if(num%2===0){
console.log("是偶數(shù)!")
}else{
console.log("是奇數(shù)!")
}
//判斷是否正數(shù)
if(num>0){
console.log("是正數(shù)!")
}else if(num<0){
console.log("是負(fù)數(shù)!")
}else{
console.log("是0!")
}
[LOG]: "是偶數(shù)!"
[LOG]: "是正數(shù)!"
let grade:string="A";
switch(grade){
case "A" :
console.log("優(yōu)秀")
break
case "B":
console.log("及格")
break
case "C":
console.log("不及格")
break
default:
console.log("非法輸入")
break
}
[LOG]: "優(yōu)秀"
注意:
- 在Typescript中,空字符串、數(shù)字0、null、undefind都被認(rèn)為是false,其他值則為true。
比較運(yùn)算符:== 與 ===
- 在Typescript中,比較運(yùn)算符 '=='(相等運(yùn)算符) 和 '==='(嚴(yán)格相等運(yùn)算符) 都可以用于比較兩個(gè)值是否相等,但是==如果比較的兩個(gè)值類型不同,那么它會(huì)主動(dòng)的對(duì)數(shù)據(jù)類型進(jìn)行強(qiáng)制轉(zhuǎn)換為相同的類型后再比較,這樣的話比較損耗性能。
所以建議優(yōu)先使用 === 嚴(yán)格相等運(yùn)算符。
循環(huán)迭代
Typescript支持for和while循環(huán),并且為一些內(nèi)置類型如Array等提供了快捷迭代語(yǔ)法。
- for:常規(guī)for循環(huán)。
- while:常規(guī)while循環(huán)。
- for in 遍歷:得到數(shù)組索引角標(biāo)。
- for of遍歷:得到數(shù)組元素。
//for循環(huán)
for(let i=0;i<10;i++){
//輸出0-9
console.log("for循環(huán),i="+i)
}
//while循環(huán)
let i=0;
while(i<10){
//輸出0-9
console.log("while循環(huán),i="+i)
i++;
}
let list:Array<string>=['A','B','C','D','E']
//for in 迭代器,遍歷得到數(shù)組角標(biāo)索引。
for(const i in list){
//輸出數(shù)組角標(biāo)
console.log("for in 迭代獲取list角標(biāo),i="+i)
//輸出數(shù)組的元素內(nèi)容
console.log("for in 迭代打印數(shù)組內(nèi)容,第"+i+"個(gè)為"+list[i])
}
//for of 迭代器,遍歷得到數(shù)組元素
for(const item of list){
//輸出數(shù)組內(nèi)的元素內(nèi)容
console.log("for of 迭代打印list數(shù)組內(nèi)容, item="+item)
}
函數(shù)
Typescript通常利用function關(guān)鍵字聲明函數(shù),并且支持可選參數(shù)、默認(rèn)參數(shù)、箭頭函數(shù)等特殊語(yǔ)法。
- 無返回值函數(shù)
- 有返回值函數(shù)
- 箭頭函數(shù)
語(yǔ)法:let 函數(shù)名 =(參數(shù)名:參數(shù)類型)=>{ ... } 代碼塊內(nèi)部可以 return 返回任意類型的數(shù)據(jù)。
//無返回值函數(shù),返回值void可以省略。
function sayHello(name:string):void{//:void 表示無返回值,可省略。
console.log("你好,"+name)
}
sayHello("張三")
//有返回值的函數(shù)
function sum(x:number,y:number):number{
return x+y;
}
console.log("1+1="+sum(1,1));
//箭頭函數(shù)
let sayHi=(name:string)=>{
console.log("你好,"+name)
}
sayHi("李四")
可選參數(shù)
可選參數(shù),表示函數(shù)在被調(diào)用時(shí),可選參數(shù)是可以不傳值的。
//可選參數(shù),在參數(shù)名后面添加?符號(hào),表示該參數(shù)是可選的
function sayHello(name?:string){
console.log(name)//輸出:undefined
//檢查是否為name參數(shù)傳入值
name=name?name:"陌生人"
console.log("你好,"+name)//輸出:"你好,陌生人"
}
sayHello()
默認(rèn)參數(shù)
默認(rèn)參數(shù),表示參數(shù)具有默認(rèn)值,如果調(diào)用時(shí)該參數(shù)未傳值,則使用默認(rèn)值。
//默認(rèn)參數(shù),在參數(shù)類型后面添加 ="默認(rèn)值"
function sayHello(name:string="陌生人"){
console.log(name)//輸出:陌生人
//檢查是否為name參數(shù)傳入值
name=name?name:"陌生人"
console.log("你好,"+name)//輸出:你好,陌生人
}
sayHello()
類和接口
Typescript具備面向?qū)ο缶幊痰幕菊Z(yǔ)法,例如interface、class、enum等。也具備封裝、繼承、多態(tài)等面向?qū)ο蠡咎卣鳌?/p>
//定義枚舉
enum Msg{
HI="Hi",
HELLO="Hello",
}
//定義接口
interface A{
say(msg:Msg):void
}
//實(shí)現(xiàn)接口
class B implements A{
say(msg:Msg):void{
console.log(msg+",I'm B")
}
}
//創(chuàng)建B的實(shí)例對(duì)象
let b:B=new B();
b.say(Msg.HELLO)
//輸出:"Hello,I'm B"
總結(jié):
-
- 枚舉支持賦值(支持任意類型,不需要聲明),如果不賦值,則默認(rèn)從0開始,按照順序每個(gè)枚舉值默認(rèn)+1。
- 如果枚舉中有一個(gè)成員定義了值,那么其他枚舉元素也必須要定義值,無法再使用默認(rèn)的值。
- 枚舉中每個(gè)成員的數(shù)據(jù)類型可以存在不同。
- 在接口中定義的函數(shù)、類中實(shí)現(xiàn)的接口函數(shù)中,函數(shù)不需要添加function關(guān)鍵字。
- Typescript中對(duì)象的創(chuàng)建是通過new關(guān)鍵字來實(shí)現(xiàn)的。
類
//定義矩形類
class Rectangle{
//成員變量
//定義類中成員變量時(shí),不需要添加let關(guān)鍵字。
//private關(guān)鍵字表示當(dāng)前成員變量為私有的。成員變量默認(rèn)的訪問權(quán)限是public。
private mWidth:number
private mLength:number
//構(gòu)造函數(shù)
constructor(width:number,length:number){
//在函數(shù)中操作成員變量時(shí),必須用 this 去獲取變量。不使用this的話就無法操作成員變量。
this.mWidth=width
this.mLength=length
}
//成員函數(shù)
public area():number{
return this.mWidth+this.mLength
}
}
//定義正方形類
class Square extends Rectangle{
//定義構(gòu)造函數(shù)
constructor(side:number){
//調(diào)用父類的構(gòu)造函數(shù)
super(side,side)
}
}
let sq=new Square(5)
console.log("正方形的面積為:"+sq.area())
//輸出:"正方形的面積為:10"
總結(jié):
- 定義類中的成員變量時(shí),不需要添加let關(guān)鍵字。
- 在類函數(shù)中操作當(dāng)前類的成員變量時(shí),必須用 this 去獲取變量。不使用this的話就無法操作成員變量。、
- 類的構(gòu)造函數(shù)不需要函數(shù)名。
- 在 TypeScript 中,類的成員(包括屬性和方法)的訪問權(quán)限默認(rèn)是 public。
TypeScript中的訪問修飾符:public、private、protected
- extends:繼承。
get、set函數(shù)
private 修飾的成員變量是受保護(hù)的,在類的外面無法進(jìn)行直接賦值和取值;但是是可以使用 get、set 方法來對(duì) private 修飾的成員變量進(jìn)行賦值和取值
在Typescript中也有g(shù)et、set函數(shù);它們的使用方式為:
- get 函數(shù)名():變量類型
- set 函數(shù)名(入?yún)ⅲ鹤兞款愋?
注意:
- 使用 get、set方法的成員變量命名時(shí)建議在前面加 _
- get 和 set 方法的名稱,建議使用去掉 _ 的成員變量名稱
- 在類外使用時(shí),通過操作get和set修飾的方法名(以對(duì)象屬性的方式操作),來間接的操作成員變量
export class NameBean{
private _name:string;//名稱
get name():string{
return this._name
}
set name(setName:string){
this.name=setName
}
}
模塊開發(fā)
當(dāng)應(yīng)用復(fù)雜時(shí),我們可以把通用功能抽取到單獨(dú)的TS文件中,每個(gè)TS文件都是一個(gè)模塊(moudle)。模塊可以相互加載,提高代碼復(fù)用性。
在Typescript中,我們可以將想要提供給其他TS文件使用的函數(shù)、變量、類進(jìn)行導(dǎo)出(export),如下代碼:
使用export修飾class、 function,從而導(dǎo)出給其他TS文件使用。
//定義矩形類,并使用export導(dǎo)出。
export class Rectangle{
//成員變量
public mWidth:number
public mLength:number
//構(gòu)造函數(shù)
constructor(width:number,length:number){
this.mWidth=width
this.mLength=length
}
}
export function area(rec:Rectangle):number{
return rec.mWidth+rec.mLength
}
在其他模塊(TS文件)中,將可導(dǎo)出的功能導(dǎo)入(import)到當(dāng)前模塊內(nèi)使用:
//通過import語(yǔ)法導(dǎo)入其他TS文件的功能,from后面寫文件的地址
//import語(yǔ)句建議放在代碼頂部。
import {Rectangle,area} from '../rectangle'
//導(dǎo)入功能后,可以在當(dāng)前文件內(nèi)任意地方進(jìn)行Rectangle、area的調(diào)用。
//創(chuàng)建Rectangle對(duì)象
let r = new Rectangle(10,20)
//調(diào)用area方法
console.log("面積為:"+area(r))
了解Harmony基本工程目錄
Ohos項(xiàng)目結(jié)構(gòu)分類
將項(xiàng)目的目錄視圖,切換到鴻蒙的Ohos視圖
- AppScope中存放應(yīng)用全局所需要的資源文件。
- Entry是entry是應(yīng)用的主模塊,存放HarmonyOS應(yīng)用的代碼、資源等。
-
- ets文件夾內(nèi)存放代碼編寫文件(我們開發(fā)主要集中在ets文件夾中)
-
-
- page存放頁(yè)面 :index.ets是初始頁(yè)面
-
- configuration則存放相應(yīng)模塊配置文件
- resources對(duì)應(yīng)文件公共資源
- 最外層的configuration,存放工程應(yīng)用級(jí)的配置文件
-
- build-profile.json5是工程級(jí)配置信息,包括簽名、產(chǎn)品配置等。
- hvigorfile.ts是工程級(jí)編譯構(gòu)建任務(wù)腳本,hvigor是基于任務(wù)管理機(jī)制實(shí)現(xiàn)的一款全新的自動(dòng)化構(gòu)建工具,主要提供任務(wù)注冊(cè)編排,工程模型管理、配置管理等核心能力。
- oh-package.json5是工程級(jí)依賴配置文件,用于記錄引入包的配置信息。
- 在AppScope,其中有resources文件夾和配置文件app.json5。AppScope > resources> base文件夾中包含element和media兩個(gè)文件夾
-
- 其中element文件夾主要存放公共的字符串、布局文件等資源。
- media存放全局公共的多媒體資源文件。
- 將項(xiàng)目切換到 project 視圖:oh_modules 是工程的依賴包,存放工程依賴的源文件。
module結(jié)構(gòu)分類
接下來看模塊中的結(jié)構(gòu)分類:
- entry模塊下的src目錄中主要包含總的main文件夾,單元測(cè)試目錄ohosTest,以及模塊級(jí)的配置文件。
- main文件夾中,ets文件夾用于存放ets代碼,resources文件存放模塊內(nèi)的多媒體及布局文件等,module.json5文件為模塊的配置文件。
- ohosTest是單元測(cè)試目錄。
- build-profile.json5是模塊級(jí)配置信息,包括編譯構(gòu)建配置項(xiàng)。
- hvigorfile.ts文件是模塊級(jí)構(gòu)建腳本。
- oh-package.json5是模塊級(jí)依賴配置信息文件。
- 進(jìn)入src>main>ets目錄中,其分為entryability、pages兩個(gè)文件夾。
-
- entryability存放ability文件,用于當(dāng)前ability應(yīng)用邏輯和生命周期管理。
- pages存放UI界面相關(guān)代碼文件,初始會(huì)生成一個(gè)Index頁(yè)面。
- resources目錄下存放模塊公共的多媒體、字符串及布局文件等資源,分別存放在element、media文件夾中。
app.json5
AppScope下的app.json5是應(yīng)用的全局的配置文件,用于存放應(yīng)用公共的配置信息。
其中配置信息如下:
- bundleName是包名。
- vendor是應(yīng)用程序供應(yīng)商。
- versionCode是用于區(qū)分應(yīng)用版本。
- versionName是版本號(hào)。
- icon對(duì)應(yīng)于應(yīng)用的顯示圖標(biāo)。
- label是應(yīng)用名。
module.json5
模塊的配置文件,包含當(dāng)前模塊的配置信息。mainElement指定啟動(dòng)首頁(yè)Ability的名稱,abilities中可以聲明多個(gè)Ability。
deviceTypes:聲明了當(dāng)前模塊支持的設(shè)備類型,這里是手機(jī)phone和平板tablet。
entry>src>main>module.json5是模塊的配置文件,包含當(dāng)前模塊的配置信息。
我們簡(jiǎn)單了解以下幾個(gè):
name :該標(biāo)簽標(biāo)識(shí)當(dāng)前module的名字,module打包成hap后,表示hap的名稱,標(biāo)簽值采用字符串表示(最大長(zhǎng)度31個(gè)字節(jié)),該名稱在整個(gè)應(yīng)用要唯一;如 entry。
mainElement :指定啟動(dòng)首頁(yè)Ability的名稱;該標(biāo)簽標(biāo)識(shí)模塊的入口ability名稱或者extension名稱;如 EntryAbility。
deviceTypes :該標(biāo)簽標(biāo)識(shí)hap可以運(yùn)行在哪類設(shè)備上,標(biāo)簽值采用字符串?dāng)?shù)組的表示。如 ["phone",tablet"] 表示當(dāng)前模塊可以運(yùn)行在手機(jī)和平板上。
pages :對(duì)應(yīng)的是main_pages.json文件,用于配置ability中用到的page信息。
abilities :是一個(gè)數(shù)組,存放當(dāng)前模塊中所有的ability元能力的配置信息,其中可以有多個(gè)ability。
-
name :該標(biāo)簽標(biāo)識(shí)當(dāng)前ability的邏輯名,該名稱在整個(gè)應(yīng)用要唯一,標(biāo)簽值采用字符串表示(最大長(zhǎng)度127個(gè)字節(jié))。
srcEntry :當(dāng)前模塊的入口Ability文件路徑。 如:"./ets/entryability/EntryAbility.ts"
{
"module": {
//name:該標(biāo)簽標(biāo)識(shí)當(dāng)前module的名字,module打包成hap后,表示hap的名稱,標(biāo)簽值采用字符串表示(最大長(zhǎng)度31個(gè)字節(jié)),該名稱在整個(gè)應(yīng)用要唯一。
"name": "entry",
//type: 表示模塊的類型,類型有三種,分別是entry、feature和har。
"type": "entry",
//description:當(dāng)前模塊的描述信息。
"description": "$string:module_desc",
//mainElement: 該標(biāo)簽標(biāo)識(shí)hap的入口ability名稱或者extension名稱。只有配置為mainElement的ability或者extension才允許在服務(wù)中心露出。
"mainElement": "EntryAbility",
//deviceTypes:該標(biāo)簽標(biāo)識(shí)hap可以運(yùn)行在哪類設(shè)備上,標(biāo)簽值采用字符串?dāng)?shù)組的表示。
"deviceTypes": [
"phone",
"tablet"
]],
//deliveryWithInstall:標(biāo)識(shí)當(dāng)前Module是否在用戶主動(dòng)安裝的時(shí)候安裝,表示該Module對(duì)應(yīng)的HAP是否跟隨應(yīng)用一起安裝。
// - true:主動(dòng)安裝時(shí)安裝。- false:主動(dòng)安裝時(shí)不安裝。
"deliveryWithInstall": true,
//installationFree:標(biāo)識(shí)當(dāng)前Module是否支持免安裝特性。- true:表示支持免安裝特性,且符合免安裝約束。- false:表示不支持免安裝特性。
"installationFree": false,
//pages:對(duì)應(yīng)的是main_pages.json文件,用于配置ability中用到的page信息。
"pages": "$profile:main_pages",
//abilities:是一個(gè)數(shù)組,存放當(dāng)前模塊中所有的ability元能力的配置信息,其中可以有多個(gè)ability。
"abilities": [
{
//name:該標(biāo)簽標(biāo)識(shí)當(dāng)前ability的邏輯名,該名稱在整個(gè)應(yīng)用要唯一,標(biāo)簽值采用字符串表示(最大長(zhǎng)度127個(gè)字節(jié))。
"name": "EntryAbility",
//srcEntry:當(dāng)前模塊的入口文件路徑。
"srcEntry": "./ets/entryability/EntryAbility.ts",
//description:ability的描述信息。
"description": "$string:EntryAbility_desc",
// icon:ability的圖標(biāo)。該標(biāo)簽標(biāo)識(shí)ability圖標(biāo),標(biāo)簽值為資源文件的索引。該標(biāo)簽可缺省,缺省值為空。
// 如果ability被配置為MainElement,該標(biāo)簽必須配置。
"icon": "$media:icon",
//label: ability的標(biāo)簽名。
"label": "$string:EntryAbility_label",
//startWindowIcon 啟動(dòng)頁(yè)面的圖標(biāo)。
"startWindowIcon": "$media:icon",
//startWindowBackground: 啟動(dòng)頁(yè)面的背景色。
"startWindowBackground": "$color:start_window_background",
"exported": true,
// skills:標(biāo)識(shí)能夠接收的意圖的action值的集合,取值通常為系統(tǒng)預(yù)定義的action值,也允許自定義。
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
// visible:ability是否可以被其他應(yīng)用程序調(diào)用,true表示可以被其它應(yīng)用調(diào)用, false表示不可以被其它應(yīng)用調(diào)用。
// entities:標(biāo)識(shí)能夠接收Want的Entity值的集合。
// actions:標(biāo)識(shí)能夠接收的Want的Action值的集合,取值通常為系統(tǒng)預(yù)定義的action值,也允許自定義。
}
]
}
}
main_pages.json
entry/src/main/resources/base/profile/main_pages.json文件保存的是當(dāng)前模塊中頁(yè)面page的路徑配置信息,所有需要進(jìn)行路由跳轉(zhuǎn)的page頁(yè)面都要在這里進(jìn)行配置。
index.ets
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.fontColor("#36D")
// .onClick(()=>{
// //處理事件
// })
.onClick((event)=>{
//處理??件
})
.width('100%')
}
.height('100%')
}
}
- struct index{ }:在上述代碼中聲明了一個(gè)自定義組件index,自定義組件是可復(fù)用的UI單元。
但是自定義組件不能僅僅靠關(guān)鍵詞struct,還需要添加 裝飾器 標(biāo)記來聲明當(dāng)前結(jié)構(gòu)體的信息。
被 @Component 裝飾器修飾的結(jié)構(gòu)體,才能稱為自定義結(jié)構(gòu)體組件。
從java注解漫談到typescript裝飾器——注解與裝飾器
- 裝飾器:用來裝飾類結(jié)構(gòu)、方法、變量
-
- @Entry:用來修飾結(jié)構(gòu)體組件;標(biāo)記當(dāng)前組件是入口組件,也就是當(dāng)前組件是支持被獨(dú)立訪問的。即一個(gè)頁(yè)面。
如果組件不添加@Entry,那么這個(gè)組件就是普通組件。
預(yù)覽器只會(huì)預(yù)覽使用了@Enrty裝飾器的組件。
- @Component:用來修飾結(jié)構(gòu)體組件;標(biāo)記聲明為 自定義組件
- @State:用來修飾變量;標(biāo)記這個(gè)變量為狀態(tài)變量,值變化時(shí)會(huì)觸發(fā)對(duì)應(yīng)的UI刷新。
- build(){ } 函數(shù):其內(nèi)部以聲明式方式描述UI結(jié)構(gòu)。
如上述代碼中的Row()、Column()、Text()都是ArkTS提供的組件。
這些組件也分為兩類:
-
- 容器組件:用來完成頁(yè)面布局,例如:Row、Column。
- 基礎(chǔ)組件:自帶樣式和功能的頁(yè)面元素,例如 Text文本組件。
- UI樣式的屬性方法:設(shè)置組件的UI樣式。
通過調(diào)用自定義組件提供的屬性方法,來修改組件樣式信息,
如 fontsize()設(shè)置字體大小,fontweight設(shè)置字體粗細(xì),fontColor設(shè)置字體顏色,等等。
- UI事件方法(監(jiān)聽):設(shè)置組件的事件回調(diào)。
UI組件支持設(shè)置例如 點(diǎn)擊 等事件的監(jiān)聽。如:onClick(()=>{ //處理事件... }) 在View被點(diǎn)擊時(shí)會(huì)觸發(fā)方法塊里的代碼。
EntryAbility.ts
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index1', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}
類似Activity,這里面有很多內(nèi)置的生命周期,如創(chuàng)建、銷毀;前臺(tái)、后臺(tái)。
ArkUI-組件
ArkUI提供的常用組件
Image:圖片顯示組件
Image通常用來加載圖片顯示。
- 聲明Image組件并設(shè)置圖片源
Image(src:string|PixelMap|Resource)
入?yún)?shù)據(jù)類型介紹:
-
- string格式:通常用來加載網(wǎng)絡(luò)圖片,應(yīng)用訪問網(wǎng)絡(luò)需要聲明網(wǎng)絡(luò)訪問權(quán)限:ohos.permission.INTERNET。
Image("....png")
- PixelMap格式:可以加載像素圖,常用在圖片編輯中。該方式使用較復(fù)雜。
Image(pixelMapObject)
- Resource格式:加載資源圖片,推薦使用此種方式。
-
-
- 方式1:Image( **r??(′app.media.icon′))r 方式的路徑則是對(duì)應(yīng)了src的resource文件夾中media目錄中的icon圖標(biāo)。
該方式可以省略文件的后綴名。
- 方式2:Image( **rawfile??(′gmzr.png′))rawfile 方式則是對(duì)應(yīng)了src的resource文件夾中rawfile目錄下的 gmzr.png 文件
當(dāng)前方式不允許省略文件后綴名。
- 添加圖片屬性
Image($r("app.media.icon"))
.objectFit(ImageFit.Cover)//設(shè)置圖片縮放效果,默認(rèn)Cover
.width(50)//寬度
.height(50)//高度
.borderRadius(10)//邊框圓角,不設(shè)置時(shí)默認(rèn)方角。
.interpolation(ImageInterpolation.High)//圖片插值:將不清晰圖片的鋸齒消除,提高圖片清晰度。
圖片適應(yīng)模式
objectFit方法屬性用于設(shè)置圖片的適應(yīng)模式,參數(shù)類型是ImageFit;
ImageFit包含以下幾種類型:
- Contain:保持寬高比進(jìn)行縮小或者放大,使得圖片完全顯示在顯示邊界內(nèi)。
- Cover(默認(rèn)值):保持寬高比進(jìn)行縮小或者放大,使得圖片兩邊都大于或等于顯示邊界。
- Auto:自適應(yīng)顯示。
- Fill:不保持寬高比進(jìn)行放大縮小,使得圖片充滿顯示邊界。
- ScaleDown:保持寬高比顯示,圖片縮小或者保持不變。
- None:保持原有尺寸顯示。
網(wǎng)絡(luò)權(quán)限申請(qǐng)
加載網(wǎng)絡(luò)圖片時(shí),需要配置文件權(quán)限聲明:應(yīng)用權(quán)限列表
{
"module" : {
// ...
"requestPermissions":[
{
//申請(qǐng)網(wǎng)絡(luò)權(quán)限
"name": "ohos.permission.INTERNET",
},
{
//示例:
"name" : "ohos.permission.PERMISSION1",
"reason": "$string:reason",
"usedScene": {
"abilities": [
"FormAbility"
],
"when":"inuse"
}
}
]
}
}
UI組件寬高設(shè)置
UI組件的寬高設(shè)置有三種方式:
- 直接在width函數(shù)中寫數(shù)值,如 .width(50),這樣的話會(huì)默認(rèn)使用vp虛擬像素作為寬度的單位,即 50vp。
vp是鴻蒙的一種虛擬像素,用來適配多分辨率設(shè)備而存在,理解為安卓的dp。
推薦使用此方式。
- 使用字符串類型的數(shù)值,如 .width("50"),該方式的單位則是像素px,多分辨率下適配性會(huì)不太好。
- 使用字符串類型的百分比,如 .width("100%"),該方式的單位是百分比,表示占當(dāng)前組件父布局的百分比。
官方文檔查看快捷方式
將鼠標(biāo)懸停在組件上,點(diǎn)擊Show in API Reference,即可打開官方組件文檔。
Text:文本顯示組件
- 聲明Text組件并設(shè)置文本內(nèi)容:
Text(content?:string|Resource)
文本內(nèi)容來源有兩個(gè)方式:
- string格式:自己傳入的字符串,會(huì)直接顯示在Text組件中。
Text("文本內(nèi)容")
Text($r("app.string.EntryAbility_label"))
當(dāng)前系統(tǒng)語(yǔ)言為中文時(shí),這種方式則是從 Resource\zh_CN\string.json 文件中獲取對(duì)應(yīng)name為EntryAbility_label的值來顯示。
- 設(shè)置Text的成員屬性
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.fontColor("#36D")
-
- fontSize:設(shè)置字體大小。
- fontweight:設(shè)置字體的粗細(xì)。
- fontColor:設(shè)置文字顏色。
- 更多的API參考官方API文檔。
名稱 | 參數(shù)類型 | 描述 |
---|
fontColor | ResourceColor | 設(shè)置文本顏色。 | fontSize | Length | Resource | 設(shè)置文本尺寸,Length為number類型時(shí),使用fp單位。 | fontStyle | FontStyle | 設(shè)置文本的字體樣式。默認(rèn)值:FontStyle.Normal。 | fontWeight | number | FontWeight | string | 設(shè)置文本的字體粗細(xì),number類型取值[100, 900],取值間隔為100,默認(rèn)為400,取值越大,字體越粗。string類型僅支持number類型取值的字符串形式,例如“400”,以及“bold”、“bolder”、“l(fā)ighter”、“regular”、“medium”,分別對(duì)應(yīng)FontWeight中相應(yīng)的枚舉值。默認(rèn)值:FontWeight.Normal。 | fontFamily | string | Resource | 設(shè)置文本的字體列表。使用多個(gè)字體,使用“,”進(jìn)行分割,優(yōu)先級(jí)按順序生效。例如:“Arial,sans-serif”。 | textAlign | TextAlign | 設(shè)置文本的對(duì)齊方式。Start(默認(rèn)值):水平對(duì)齊首部。Center:水平居中對(duì)齊。 End:水平對(duì)齊尾部。 | decoration | TextDecorationType | 設(shè)置文本裝飾線樣式及其顏色。{ type: TextDecorationType.Underline, color: Color.Black } 給文本設(shè)置了下劃線,下劃線顏色為黑色 |
多語(yǔ)言適配
鴻蒙APP的多語(yǔ)言適配和Android差不多,在Resource文件夾下生成多個(gè)目錄,每個(gè)目錄按照指定的規(guī)則命名。之后APP會(huì)根據(jù)所運(yùn)行在的系統(tǒng)語(yǔ)言版本 從對(duì)應(yīng)的目錄下讀取string.json,并展示對(duì)應(yīng)文本。
base目錄:默認(rèn)目錄,當(dāng)找不到相對(duì)應(yīng)的語(yǔ)言版本時(shí),默認(rèn)從base查找。
en_US目錄:英文的資源目錄,當(dāng)系統(tǒng)語(yǔ)言為英語(yǔ)時(shí),優(yōu)先從當(dāng)前目錄下讀取文本。
zh_CN目錄:中文的資源目錄,當(dāng)系統(tǒng)語(yǔ)言為中文時(shí),優(yōu)先從當(dāng)前目錄下讀取文本。
TextInput:文本輸入框
TextInput組件用于輸入單行文本,響應(yīng)輸入事件。
- 聲明TextInput組件:
TextInput({placeholder?:ResourceStr,text?:ResourceStr})
-
- placeholder:輸入框無文本時(shí)的提示文本
- text:輸入框當(dāng)前的文本內(nèi)容
@State mImgWidth: number = 300
TextInput({
placeholder: "請(qǐng)輸入指定寬度",
text: "" + this.mImgWidth
})
.type(InputType.Number)
.onChange((value) => {
if (value != this.mImgWidth.toString() && value.length > 0) {
this.mImgWidth = Number.parseInt(value)
}
})
- 添加屬性和事件
TextInput({text:"當(dāng)前輸入文本"})
.width(150)//寬
.height(30)//高
.backgroundColor("#FFF")//輸入框背景色
.type(InputType.Password)//輸入框類型,如密碼類型
.onChange((value) => {//設(shè)置文字變化監(jiān)聽
if (value != this.mImgWidth.toString() && value.length > 0) {
this.mImgWidth = Number.parseInt(value)
}
})
-
- width:寬度。
- height:高度。
- backgroundColor:輸入框背景色。
- type:設(shè)置輸入類型。
名稱 | 描述 |
---|
Normal | 基本輸入模式。支持輸入數(shù)字、字母、下劃線、空格、特殊字符。 | Number | 純數(shù)字輸入模式。 | PhoneNumber | 電話號(hào)碼輸入模式。支持輸入數(shù)字、+、-、*,長(zhǎng)度不限制。 | Email | 郵箱地址輸入模式。支持?jǐn)?shù)字、字母、下劃線、@字符。 | Password | 密碼輸入模式。支持輸入數(shù)字、字母、下劃線、空格、特殊字符。 |
-
- onChange((value) => {}):設(shè)置文字輸入變化事件監(jiān)聽
設(shè)置光標(biāo)位置
使用TextInputController動(dòng)態(tài)設(shè)置。
@Entry
@Component
struct TextInputDemo {
controller: TextInputController = new TextInputController()//創(chuàng)建控制器
build() {
Column() {
TextInput({ controller: this.controller })//在這里設(shè)置控制器
Button('設(shè)置光標(biāo)位置')
.onClick(() => {
this.controller.caretPosition(2)//事件觸發(fā)式,通過caretPosition函數(shù)來修改光標(biāo)位置。
})
}
.height('100%')
.backgroundColor(0xE6F2FD)
}
}
獲取輸入文本
我們可以給TextInput設(shè)置onChange事件,輸入文本發(fā)生變化時(shí)觸發(fā)回調(diào)
@Entry
@Component
struct TextInputDemo {
@State text: string = ''
build() {
Column() {
TextInput({ placeholder: '請(qǐng)輸入賬號(hào)' })
.caretColor(Color.Blue)
.onChange((value: string) => {
//在此處監(jiān)聽文字變化后的完整文本。
this.text = value
})
Text(this.text)
}
.alignItems(HorizontalAlign.Center)
.padding(12)
.backgroundColor(0xE6F2FD)
}
}
Button:按鈕組件
Button組件主要用來響應(yīng)點(diǎn)擊操作,可以包含子組件。
- 聲明Button組件,label是按鈕文字
Button(label?:ResourceStr)
-
- ResourceStr:可以傳普通字符串,也可以傳string文件中的文本。
- 按鈕有兩種類型,傳遞了文字則是文字型按鈕,不傳遞文字則是自定義按鈕。
-
-
- 文字型按鈕:
Button("按鈕")
-
-
- 自定義按鈕,在Button內(nèi)嵌套其他組件:
Button(){
ImageView($r("app.media.search")).width(20).height(10)
}
- 添加屬性和事件
Button("點(diǎn)我")
.width(100)
.height(30)
.type(ButtonType.Normal)
.onclick(()=>{
//處理點(diǎn)擊事件
})
-
- Capsule:膠囊型按鈕(圓角默認(rèn)為高度的一半)
- Circle:圓形按鈕
- Normal:普通按鈕(默認(rèn)不帶圓角)
LoadingProgress:加載中組件
LoadingProgress組件用于顯示加載進(jìn)展,比如應(yīng)用的登錄界面,當(dāng)我們點(diǎn)擊登錄的時(shí)候,顯示的“正在登錄”的進(jìn)度條狀態(tài)。LoadingProgress的使用非常簡(jiǎn)單,只需要設(shè)置顏色和寬高就可以了。
LoadingProgress()
.color(Color.Blue)
.height(60)
.width(60)
Slider:滑動(dòng)條組件
- 滑動(dòng)條組件聲明:
Slider(options?:SliderOptions)
滑動(dòng)條組件在創(chuàng)建時(shí),支持傳入 SliderOption 類型的對(duì)象(不傳入則使用默認(rèn)樣式),SliderOption 類型中聲明了一些的滑動(dòng)條組件的UI屬性。
-
- min:最小值。
- max:最大值。
- value:當(dāng)前默認(rèn)值。
- setp:滑動(dòng)時(shí)的步長(zhǎng)。
- style:默認(rèn)OutSet:滑塊在滑條外面。 SliderStyle.inset:滑塊在滑條里面。
- direction:滑動(dòng)條方向水平或垂直。
- reverse:是否反轉(zhuǎn)滑動(dòng)條的滑動(dòng)方向。
false時(shí):水平滑動(dòng)條,左邊為起始位,右邊為終點(diǎn);垂直滑動(dòng)條,下面起始位,上面終點(diǎn)位。
true時(shí):則相反。
Slider({
min:0,//最小值
max:100,//最大值
value:50,//當(dāng)前值
step:1,//滑動(dòng)步長(zhǎng)
style:SliderStyle.OutSet,//默認(rèn)OutSet:滑塊在滑條外面。 另一個(gè)inset:滑塊在滑條里面。
direction:Axis.Horizontal,//滑動(dòng)條水平 或 垂直
reverse:false//是否反向滑動(dòng)。
})
- 更多屬性、事件。
-
- showTips:是否展示value的百分比提示。
- blockColor:滑塊的顏色
- trackThickness:滑動(dòng)條的粗細(xì)
- onchange((value)=>{}):監(jiān)聽滑塊滑動(dòng)時(shí)值的變更。value就是滑塊當(dāng)前值
.width("90%")
.showTips(true)//是否展示value百分比提示
.blockColor("#36d")//滑塊的顏色
.trackThickness(5)//滑動(dòng)條的粗細(xì)
.onChange((value)=>{//監(jiān)聽滑塊滑動(dòng)時(shí)值的變更。
//value就是滑??當(dāng)前值
this.mImgWidth=value
})
使用資源引用類型
Resource是資源引用類型,用于設(shè)置組件屬性的值。推薦大家優(yōu)先使用Resource類型,將資源文件(字符串、圖片、音頻等)統(tǒng)一存放于resources目錄下,便于開發(fā)者統(tǒng)一維護(hù)。同時(shí)系統(tǒng)可以根據(jù)當(dāng)前配置加載合適的資源,例如,開發(fā)者可以根據(jù)屏幕尺寸呈現(xiàn)不同的布局效果,或根據(jù)語(yǔ)言設(shè)置提供不同的字符串。
例如下面的這段代碼,直接在代碼中寫入了字符串和數(shù)字這樣的硬編碼。
Button('登錄', { type: ButtonType.Capsule, stateEffect: true })
.width(300)
.height(40)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.backgroundColor('#007DFF')
我們可以將這些硬編碼寫到entry/src/main/resources下的資源文件中。
在string.json中定義Button顯示的文本。
{
"string": [
{
"name": "login_text",
"value": "登錄"
}
]
}
在float.json中定義Button的寬高和字體大小。
{
"float": [
{
"name": "button_width",
"value": "300vp"
},
{
"name": "button_height",
"value": "40vp"
},
{
"name": "login_fontSize",
"value": "18fp"
}
]
}
在color.json中定義Button的背景顏色。
{
"color": [
{
"name": "button_color",
"value": "#1890ff"
}
]
}
然后在Button組件通過“$r('app.type.name') ”的形式引用應(yīng)用資源。
app 代表應(yīng)用內(nèi)resources目錄中定義的資源;
type 代表資源類型(或資源的存放位置),可以取“color”、“float”、“string”、“plural”、“media”;
name 代表資源命名,由開發(fā)者定義資源時(shí)確定。
Button($r('app.string.login_text'), { type: ButtonType.Capsule })
.width($r('app.float.button_width'))
.height($r('app.float.button_height'))
.fontSize($r('app.float.login_fontSize'))
.backgroundColor($r('app.color.button_color'))
ArkUI-容器組件
Column和Row容器
當(dāng)容器內(nèi)部有多個(gè)組件時(shí),Column(列)會(huì)將內(nèi)部組件從上往下排列,等于安卓垂直方向的LinearLayout;
而Row(行)容器會(huì)將內(nèi)部組件從左向右排列,等于安卓水平方向的LinearLayout。
主軸與交叉軸
已知我們的兩個(gè)容器它們內(nèi)部元素的排列是有方向的,那么它們排列方向的那條中間軸稱之為主軸,與之垂直的稱為交叉軸。我們?nèi)萜髦薪M件的對(duì)齊則是圍繞這兩個(gè)軸來實(shí)現(xiàn)的。
容器提供了以下兩個(gè)方法,用來調(diào)整容器內(nèi)元素的對(duì)齊方式:
屬性方法名 | 說明 | 參數(shù) |
---|
justifyContent | 設(shè)置子元素在主軸方向的對(duì)齊格式 | FlexAlign枚舉 | alignItems | 設(shè)置子元素在交叉軸方向的對(duì)齊格式 | Row容器使用VerticalAlign枚舉;Column容器使用HorizontalAlign枚舉。 |
設(shè)置主軸對(duì)齊方式
枚舉 | 功能 |
---|
FlexAlign.start | 主軸方向,內(nèi)部元素默認(rèn)往主軸起始位置靠攏。 | FlexAlign.center | 主軸方向,內(nèi)部元素默認(rèn)往主軸中間位置靠攏。 | FlexAlign.end | 主軸方向,內(nèi)部元素默認(rèn)往主軸終點(diǎn)位置靠攏。 | FlexAlign.SpaceBetween | 主軸方向,頭尾的元素貼近起點(diǎn)/終點(diǎn),其余元素居中平分間距。 | FlexAlign.SpaceAround | 主軸方向,頭尾的元素靠近起點(diǎn)/終點(diǎn)(頭尾元素間距為其他元素間距的一半),其余元素居中平分剩余間距。 | FlexAlign.SpaceEvenly | 主軸方向,所有元素靠近主軸中間,平分間距。 |
設(shè)置交叉軸對(duì)齊方式
VerticalAlign
因?yàn)镽ow容器內(nèi)部元素是水平排列的,所以交叉軸是垂直的,因此使用VerticalAlign,控制垂直方向的元素排列。
枚舉 | 功能 |
---|
VerticalAlign.start | 垂直方向,靠近交叉軸的起始位置。 | VerticalAlign.center | 垂直方向,靠近交叉軸的中間位置。 | VerticalAlign.end | 垂直方向,靠近交叉軸的終點(diǎn)位置。 |
HorizontalAlign
因?yàn)镃olumn容器內(nèi)部元素是垂直排列的,所以交叉軸是水平的,因此使用HorizontalAlign,控制水平方向的元素排列。
枚舉 | 功能 |
---|
HorizontalAlign.start | 水平方向,靠近交叉軸的起始位置。 | HorizontalAlign.center | 水平方向,靠近交叉軸的中間位置。 | HorizontalAlign.end | 水平方向,靠近交叉軸的終點(diǎn)位置。 |
設(shè)置元素內(nèi)、外邊距
每個(gè)UI組件都支持設(shè)置自身的內(nèi)外邊距。內(nèi)邊距使用padding(),外邊距使用margin()。
margin(value: Margin | Length)
padding(value: Padding | Length)
參數(shù)說明:
- Length類型:支持傳入string、number、Resource三種類型。如: "1%",10,r、rawfile方式。
.margin(20)//設(shè)置上下左右邊距為20
- Margin類型:Margin是一個(gè)對(duì)象,它里面有四個(gè)參數(shù):
-
- top:上邊距。
- bottom:下邊距。
- left:左邊距。
- right:右邊距。
- 以上四個(gè)參數(shù)可以選擇性設(shè)置,不設(shè)置則默認(rèn)0。
.margin({top:20,bottom:20,left:0,right:0})//設(shè)置top、bottom、left、right邊距。
.margin({top:20,bottom:20})//只設(shè)置top、bottom的邊距,其他的不設(shè)置。
blank組件
blan組件是個(gè)空組件,主要用來占位,它會(huì)占滿當(dāng)前父容器主軸方向的空閑位置。
比如我寫了一個(gè)布局:一個(gè)Row容器,內(nèi)部由3個(gè)組件構(gòu)成,分別為返回鍵、標(biāo)題、刷新按鈕;
我想使返回按鈕和標(biāo)題欄居左,而刷新按鈕居右。
此時(shí)則可以在標(biāo)題欄 和 刷新按鈕的中間放置一個(gè)Blank組件,這樣一來,刷新按鈕就被擠到了右側(cè)。
案例:圖片放大縮小頁(yè)面
使用前面學(xué)習(xí)的Ark常用組件來完成圖片放大縮小頁(yè)面的開發(fā)。
效果圖:
功能介紹:
- 布局使用Column、Row容器;圖片組件使用Image、輸入框使用TextInput、文本顯示使用Text、放大/縮小按鈕使用Button、滑動(dòng)條使用Slider。
- 當(dāng)修改圖片寬度文字時(shí),調(diào)整Image的寬度使其呈現(xiàn)放大效果,同時(shí)拖動(dòng)條位置也跟隨變化。
- 當(dāng)點(diǎn)擊放大/縮小按鈕時(shí),Image放大/縮小,同時(shí)拖動(dòng)條與圖片寬度文字也同步更新。
- 當(dāng)拖動(dòng)Slider時(shí),Image跟隨滑動(dòng)變化,同時(shí)圖片寬度文字同步更新。
完成代碼:Linxy/鴻蒙應(yīng)用開發(fā)入門代碼倉(cāng)庫(kù)
@Entry
@Component
struct Index {
@State message: string = 'Hello World'
@State mImgWidth: number = 300 //用來修飾變量;標(biāo)記這個(gè)變量為狀態(tài)變量,值變化時(shí)會(huì)觸發(fā)對(duì)應(yīng)的UI刷新。
build() {
Row() {
Column() {
Image($rawfile("gmzr.png"))//添加rawfile文件夾下的資源文件
.width(this.mImgWidth)//組件的寬度綁定mImgWidth
.height(400)//高設(shè)置為400vp
.interpolation(ImageInterpolation.High)//去除圖片鋸齒
Row() {
Text("圖片寬度")//文字文本
TextInput({
placeholder: "請(qǐng)輸入指定寬度",//提示詞,類似hint
text: this.mImgWidth.toFixed(0)//獲取mImgWidth的文本,包含小數(shù)點(diǎn)后0位。
})
.type(InputType.Number)//只允許輸入數(shù)字
.onChange((value) => {
//輸入文字監(jiān)聽
if (value != this.mImgWidth.toString() && value.length > 0) {
this.mImgWidth = Number.parseInt(value)
}
})
.width(200)
}
.width("90%")
.justifyContent(FlexAlign.SpaceBetween)//主軸對(duì)齊方式:頭尾的元素貼近起點(diǎn)/終點(diǎn),其余元素居中平分間距。
.alignItems(VerticalAlign.Center)//內(nèi)部元素沿交叉軸居中,row容器中交叉軸為垂直,所以這里效果為元素上下居中。
.margin({top:20,bottom:20,left:0,right:0})//設(shè)置容器的外邊距
Row() {
Button("放大")
.width(80)
.height(30)
.onClick(() => {
//監(jiān)聽點(diǎn)擊事件
if (this.mImgWidth < SLIDER_MAX) {
if (this.mImgWidth + 50 > SLIDER_MAX) {
this.mImgWidth = SLIDER_MAX
} else {
this.mImgWidth += 50
}
}
})
.type(ButtonType.Normal)//按鈕使用默認(rèn)的方形樣式
Button("縮小")
.width(80)
.height(30)
.onClick(() => {
if (this.mImgWidth > SLIDER_MIN) {
if (this.mImgWidth - 50 < SLIDER_MIN) {
this.mImgWidth = SLIDER_MIN
} else {
this.mImgWidth -= 50
}
}
})
.type(ButtonType.Normal)
}.width("100%")//寬度為父容器的百分百,占滿
.justifyContent(FlexAlign.SpaceEvenly)//主軸方向,所有元素靠近主軸中間,平分間距。 左右居中等間距。
Slider({
min: SLIDER_MIN, //最小值
max: SLIDER_MAX, //最大值
value: this.mImgWidth, //當(dāng)前值
step: 1, //滑動(dòng)步長(zhǎng)
style: SliderStyle.OutSet, //默認(rèn)OutSet:滑塊在滑條外面。 另一個(gè)inset:滑塊在滑條里面。
direction: Axis.Horizontal, //滑動(dòng)條水平 或 垂直
reverse: false //是否反向滑動(dòng)
})
.width("90%")
.showTips(true) //是否展示value百分比提示
.blockColor("#36d") //滑塊的顏色
.trackThickness(5) //滑動(dòng)條的粗細(xì)
.onChange((value) => { //監(jiān)聽滑塊滑動(dòng)時(shí)值的變更。
//value就是滑塊當(dāng)前值
this.mImgWidth = value
})
}
.height('100%')
// .justifyContent(FlexAlign.SpaceEvenly)
.justifyContent(FlexAlign.Center)//主軸方向居中,這里是Column主軸垂直,即垂直居中。
}
.height('100%')
}
}
const SLIDER_MIN = 0;
const SLIDER_MAX = 2000;
function name(params) {
}
布局檢查器
在DevEcoStudio編譯器中,點(diǎn)擊Previewer查看預(yù)覽視圖,再點(diǎn)擊Inspector打開布局檢查功能。
打開布局檢查功能后,就能夠點(diǎn)擊預(yù)覽頁(yè)面的視圖、或者點(diǎn)擊ComponentTree中的item項(xiàng),編譯器會(huì)自動(dòng)幫助我們定位到對(duì)應(yīng)的代碼塊,并展示UI相關(guān)的其他信息及獲取布局結(jié)構(gòu)。
容器內(nèi)元素間距space
Row容器和Column容器都支持設(shè)置內(nèi)部元素間的間距值,用法為:
Row({space:20}) {...}
Coloumn({space:20}) {...}
RelativeContainer相對(duì)布局
RelativeContainer是一個(gè)相對(duì)布局容器,通常用于復(fù)雜場(chǎng)景中元素對(duì)齊的布局。
- 容器內(nèi)的組件區(qū)分 水平方向 和 垂直方向:
-
- 水平方向?yàn)閘eft, middle, right,對(duì)應(yīng)容器的HorizontalAlign.Start, HorizontalAlign.Center, HorizontalAlign.End。
- 垂直方向?yàn)閠op, center, bottom,對(duì)應(yīng)容器的VerticalAlign.Top, VerticalAlign.Center, VerticalAlign.Bottom。
- 容器內(nèi)的組件必須設(shè)置ID,如果不設(shè)置ID,那么該組件則不會(huì)被顯示。
- 容器內(nèi)組件主要通過設(shè)置alignRules屬性來決定位置的擺放規(guī)則:
RelativeContainer() {
Button()
.id('ConfigBtn')
.alignRules({
left: { anchor: '__container__', align: HorizontalAlign.Start },
top: { anchor: '__container__', align: VerticalAlign.Top },
})
}
- alignRules函數(shù)的參數(shù)是一個(gè) AlignRuleOption 接口,AlignRuleOption 接口中有六個(gè)屬性,分別是:
-
- 水平方向上的:left、middle、right,即左中右。
- 垂直方向上的:top、center、bottom,即上中下。
它們對(duì)應(yīng)著組件的指定位置的對(duì)齊規(guī)則。
- AlignRuleOption中的屬性是對(duì)象,它們由兩個(gè)參數(shù)構(gòu)成:
-
- anchor:錨點(diǎn),即我們給組件設(shè)置的id,'container'表示指向當(dāng)前組件父容器。
錨點(diǎn)用于標(biāo)識(shí)當(dāng)前組件的某個(gè)位置是以該錨點(diǎn)對(duì)象作為參照物的。
- align:對(duì)齊方式,水平方向上是HorizontalAlign,垂直方向上是VerticalAlign,內(nèi)部對(duì)應(yīng)著上中,左中右。
如:left: { anchor: 'container', align: HorizontalAlign.Start },表示當(dāng)前組件的左側(cè)坐標(biāo),以父容器作為參考對(duì)象,對(duì)齊父容器的水平方向起始位置(左側(cè))。
ArkUI-循環(huán)控制/FOREACH
ArkUI中,可以通過使用FOREACH函數(shù)來生成列表視圖。
案例:
上述案例中,是一個(gè)商品列表,實(shí)現(xiàn)邏輯大致為:
- 首先抽出單條item的布局。
- 定義item所需要的數(shù)據(jù)類型Bean類。
- 定義列表,存儲(chǔ)每項(xiàng)Item的數(shù)據(jù)。
- 借助foreach循環(huán)函數(shù),根據(jù)傳入數(shù)據(jù),而生成組件并渲染
FOREACH
在ArkUI中,繪制列表需要借助FOREACH函數(shù)。
FOREACH函數(shù)共有三個(gè)入?yún)ⅲ?/p>
- Array:第一個(gè)參數(shù)是要遍歷的數(shù)據(jù)數(shù)組,即列表的數(shù)據(jù)源。
- (item:any,index?:number)=>{}:第二個(gè)參數(shù)是函數(shù)回調(diào),在此處進(jìn)行頁(yè)面組件的生成渲染。
- keyGenerator?:(item:any,index?:number):string:第三個(gè)參數(shù)也是函數(shù)回調(diào),它非常重要,我們要在函數(shù)中為item生成唯一標(biāo)識(shí)符,并作為返回值返回。(唯一標(biāo)識(shí)符,通常在Array數(shù)組內(nèi)部會(huì)有定義好的。)
FOREACH(
arr:Array,//要遍歷的數(shù)據(jù)數(shù)組
(item:any,index?:number)=>{
//頁(yè)面組件生成的函數(shù)回調(diào)
Row(){
Image(item.image)
Column(){
Text(item.name)
Text(item.price)
}
}
},
keyGenerator?:(item:any,index?:number):string => {
//定義每個(gè)item項(xiàng)的ID,必須唯一,用于列表內(nèi)部的渲染判斷
}
)
案例:實(shí)現(xiàn)一個(gè)列表
- 首先,我們先在組件中寫好item的布局:
繪制的item如下:
Row({space:20}) { //Row({space:20}) 表示設(shè)置元素間的主軸的間距為20
Image($rawfile('gmzr.png'))
.width(100)
.height(100)
Column(){
Text("商品名稱")
.fontSize(20)
.fontColor('#000000')
.fontWeight(FontWeight.Bold)
Text("商品售價(jià):¥190")
.fontSize(20)
.fontColor('#ff0000')
.fontWeight(FontWeight.Bold)
}.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.SpaceEvenly)
.height(130)
}.width('auto')
.margin({left:15,top:15,bottom:15})
}
- 定義每條Item的所需要數(shù)據(jù)類型的Bean類。
export interface ShopItemBean {
_id: number; //商品ID
_imageUrl: string; //圖片地址
_name: string; //商名稱
_price: number; //商品價(jià)格
}
- 創(chuàng)建列表的數(shù)據(jù)數(shù)組
private items: ShopItemBean[] = [
{ _id: 1, _name: '華為p10', _imageUrl: '', _price: 1 },
{ _id: 2, _name: '小米1', _imageUrl: '', _price: 2 },
{ _id: 3, _name: '華為p12', _imageUrl: '', _price: 3 },
{ _id: 4, _name: '華為p13', _imageUrl: '', _price: 4 },
{ _id: 5, _name: '華為p14', _imageUrl: '', _price: 5 },
{ _id: 6, _name: '華為p15', _imageUrl: '', _price: 6 },
{ _id: 7, _name: '華為p16', _imageUrl: '', _price: 7 },
{ _id: 8, _name: '華為p17', _imageUrl: '', _price: 8 },
{ _id: 9, _name: '華為p18', _imageUrl: '', _price: 9 },
{ _id: 10, _name: '華為p19', _imageUrl: '', _price: 10 },
{ _id: 11, _name: '華為p20', _imageUrl: '', _price: 11 },
{ _id: 12, _name: '華為p21', _imageUrl: '', _price: 12 },
];
- 使用FOREACH,繪制item
ForEach(this.items,(item:ShopItemBean,index:number)=>{
//進(jìn)行item布局的繪制
在此處放入我們第一步驟填寫的Item布局,并且將item的數(shù)據(jù)填入到item中
},(item:ShopItemBean,index?:number):string => {
//定義每個(gè)item項(xiàng)的ID,必須唯一,用于列表內(nèi)部的渲染判斷
return item.id.toString()
})
- 繪制完item后,頁(yè)面布局是滑動(dòng)不了的,還需要添加一個(gè)滑動(dòng)控件;
首先在FOREACH外面添加一個(gè)容器A,在容器A外部包裹一個(gè)scroll控件就能滑動(dòng)了。
(因?yàn)閟croll控件內(nèi)只能包裹一個(gè)控件,所以要用一個(gè)容器A來包裹FOREACH的列表item)
Scroll() {
Column() {
FOREACH(....)
}
}
完整代碼:Linxy/ArkUI實(shí)現(xiàn)列表
import { ShopItemBean } from 'ets/bean/ShopItemBean'
@Entry
@Component
struct Index2 {
private items: ShopItemBean[] = [
{ _id: 1, _name: '華為p10', _imageUrl: '', _price: 1 },
{ _id: 2, _name: '小米1', _imageUrl: '', _price: 2 },
{ _id: 3, _name: '華為p12', _imageUrl: '', _price: 3 },
{ _id: 4, _name: '華為p13', _imageUrl: '', _price: 4 },
{ _id: 5, _name: '華為p14', _imageUrl: '', _price: 5 },
{ _id: 6, _name: '華為p15', _imageUrl: '', _price: 6 },
{ _id: 7, _name: '華為p16', _imageUrl: '', _price: 7 },
{ _id: 8, _name: '華為p17', _imageUrl: '', _price: 8 },
{ _id: 9, _name: '華為p18', _imageUrl: '', _price: 9 },
{ _id: 10, _name: '華為p19', _imageUrl: '', _price: 10 },
{ _id: 11, _name: '華為p20', _imageUrl: '', _price: 11 },
{ _id: 12, _name: '華為p21', _imageUrl: '', _price: 12 },
];
build() {
Column() {
Text("商品列表")
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ left: 20 })
Scroll() {
Column() {
ForEach(this.items, (item: ShopItemBean, index: number) => {
//進(jìn)行item布局的繪制
Row() {
Image('https://img0.baidu.com/it/u=3628503530,464378779&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=800')
.width(100)
.height(100)
.borderRadius(20)
.interpolation(ImageInterpolation.High)
Column() {
Text(item._name)
.fontSize(20)
.fontColor('#000000')
.fontWeight(FontWeight.Bold)
Text("商品售價(jià):¥" + item._price)
.fontSize(20)
.fontColor('#ff0000')
.fontWeight(FontWeight.Bold)
}.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.SpaceEvenly)
.height(130)
.margin({ left: 20 })
}
.width('95%')
.margin({ top: 15, bottom: 15 })
.padding(15)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Start)
.backgroundColor('#c6c6c6')
.borderRadius(20)
}, (item: ShopItemBean, index?: number): string => {
//定義每個(gè)item項(xiàng)的ID,必須唯一,用于列表內(nèi)部的渲染判斷
return item._id.toString()
})
}.width('100%')
.alignItems(HorizontalAlign.Center)
.padding({ bottom: 70 })
}.width('auto')
.height('100%')
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Start)
.margin({ top: 30 })
}
}
ArkUI-List容器組件
上述完成了一個(gè)簡(jiǎn)單的列表頁(yè)面開發(fā),但是它存在局限性,比如說無法滑動(dòng)(需要自己去實(shí)現(xiàn))、沒有組件復(fù)用 等問題。
而List容器是正宗的列表布局容器組件(Android的RecycleView),列表容器具備以下特點(diǎn):
- 列表項(xiàng)(ListItem)數(shù)量過多超出屏幕后,會(huì)自動(dòng)提供滾動(dòng)功能。
- 列表項(xiàng)(ListItem)既可以縱向排列,也可以橫向排列。
使用方法:
List({space:10}){//列表項(xiàng)的間距
ForEach([1,2,3,4],(item:number)=>{
ListItem(){//ListItem是標(biāo)記,不是容器。
//列表項(xiàng)內(nèi)容,只能包含一個(gè)根組件
Text(item.toString())
.fontColor('#ff00ff')
.width('auto')
.height('auto')
.fontSize(20)
}
})
}.width('100%')
.listDirection(Axis.Vertical)//列表方向:默認(rèn)垂直
使用List容器實(shí)現(xiàn)商品列表頁(yè)面:
import { ShopItemBean } from 'ets/bean/ShopItemBean'
@Entry
@Component
struct Index3 {
private items: ShopItemBean[] = [
{ _id: 1, _name: '華為p10', _imageUrl: '', _price: 1 },
{ _id: 2, _name: '小米1', _imageUrl: '', _price: 2 },
{ _id: 3, _name: '華為p12', _imageUrl: '', _price: 3 },
{ _id: 4, _name: '華為p13', _imageUrl: '', _price: 4 },
{ _id: 5, _name: '華為p14', _imageUrl: '', _price: 5 },
{ _id: 6, _name: '華為p15', _imageUrl: '', _price: 6 },
{ _id: 7, _name: '華為p16', _imageUrl: '', _price: 7 },
{ _id: 8, _name: '華為p17', _imageUrl: '', _price: 8 },
{ _id: 9, _name: '華為p18', _imageUrl: '', _price: 9 },
{ _id: 10, _name: '華為p19', _imageUrl: '', _price: 10 },
{ _id: 11, _name: '華為p20', _imageUrl: '', _price: 11 },
{ _id: 12, _name: '華為p21', _imageUrl: '', _price: 12 },
];
build() {
Column() {
Text("商品列表")
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ left: 20 })
List({ space: 10 }) { //列表項(xiàng)的間距
ForEach(this.items, (item: ShopItemBean) => {
ListItem() { //ListItem是標(biāo)記,不是容器。
//列表項(xiàng)內(nèi)容,只能包含一個(gè)根組件
//進(jìn)行item布局的繪制
Row({ space: 20 }) {
Image('https://img0.baidu.com/it/u=3628503530,464378779&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=800')
.width(100)
.height(100)
.borderRadius(20)
.interpolation(ImageInterpolation.High)
Column() {
Text(item._name)
.fontSize(20)
.fontColor('#000000')
.fontWeight(FontWeight.Bold)
Text("商品售價(jià):¥" + item._price)
.fontSize(20)
.fontColor('#ff0000')
.fontWeight(FontWeight.Bold)
}.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.SpaceEvenly)
.height(130)
}
.width('95%')
.margin({ top: 15, bottom: 15 })
.padding(15)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Start)
.backgroundColor('#c6c6c6')
.borderRadius(20)
}
})
}.width('100%')
.layoutWeight(1)//注意,使用這個(gè)方式來配置好list組件的高度,如果高度沒配置好,可能會(huì)出現(xiàn)滑動(dòng),顯示不完整等問題。
//listDirection():設(shè)置List列表內(nèi)部排列方向,參數(shù)是 Axis 枚舉:默認(rèn)垂直;
// Vertical(默認(rèn)值):子組件ListItem在List容器組件中呈縱向排列。Horizontal:子組件ListItem在List容器組件中呈橫向排列。
.listDirection(Axis.Vertical)
.alignListItem(ListItemAlign.Center)//列表內(nèi)item項(xiàng)交叉軸居中
}.width('100%')
.alignItems(HorizontalAlign.Center)
}
}
設(shè)置列表分割線
List組件子組件ListItem之間默認(rèn)是沒有分割線的,部分場(chǎng)景子組件ListItem間需要設(shè)置分割線,這時(shí)候可以使用List組件的divider屬性。
divider屬性包含四個(gè)參數(shù):
- strokeWidth: 分割線的線寬。
- color: 分割線的顏色。
- startMargin:分割線距離列表側(cè)邊起始端的距離。
- endMargin: 分割線距離列表側(cè)邊結(jié)束端的距離。
List({ space: 10 }) { //列表項(xiàng)的間距
ForEach(this.items, (item: ShopItemBean) => {
ListItem() { //ListItem是標(biāo)記,不是容器。
ShopItemCard(item)
}
})
}.width('100%')
//設(shè)置分割線
.divider({strokeWidth:2,startMargin:5,endMargin:5,color:"#ff00ff"})
List列表滾動(dòng)事件監(jiān)聽
List組件提供了一系列事件方法用來監(jiān)聽列表的滾動(dòng),我們可以根據(jù)需要,監(jiān)聽這些事件來做一些操作:
- onScroll:列表滑動(dòng)時(shí)觸發(fā),返回值scrollOffset為滑動(dòng)偏移量,scrollState為當(dāng)前滑動(dòng)狀態(tài)。
- onScrollIndex:列表滑動(dòng)時(shí)觸發(fā),返回值分別為滑動(dòng)起始位置索引值與滑動(dòng)結(jié)束位置索引值。
- onReachStart:列表到達(dá)起始位置時(shí)觸發(fā)。
- onReachEnd:列表到底末尾位置時(shí)觸發(fā)。
- onScrollStop:列表滑動(dòng)停止時(shí)觸發(fā)。
List({ space: 10 }) {
ForEach(this.arr, (item) => {
ListItem() {
Text(`${item}`)
...
}
}, item => item)
}
//列表滑動(dòng)時(shí)觸發(fā),返回值分別為滑動(dòng)起始位置索引值與滑動(dòng)結(jié)束位置索引值。
.onScrollIndex((firstIndex: number, lastIndex: number) => {
console.info('first' + firstIndex)
console.info('last' + lastIndex)
})
//列表滑動(dòng)時(shí)觸發(fā),返回值scrollOffset為滑動(dòng)偏移量,scrollState為當(dāng)前滑動(dòng)狀態(tài)。
.onScroll((scrollOffset: number, scrollState: ScrollState) => {
console.info('scrollOffset' + scrollOffset)
console.info('scrollState' + scrollState)
})
// 列表到達(dá)起始位置時(shí)觸發(fā)。
.onReachStart(() => {
console.info('onReachStart')
})
// 列表到底末尾位置時(shí)觸發(fā)。
.onReachEnd(() => {
console.info('onReachEnd')
})
// onScrollStop:列表滑動(dòng)停止時(shí)觸發(fā)。
.onScrollStop(() => {
console.info('onScrollStop')
})
Grid組件的使用
Grid組件簡(jiǎn)介
Grid組件為網(wǎng)格容器,是一種網(wǎng)格列表,由“行”和“列”分割的單元格所組成,通過指定“項(xiàng)目”所在的單元格做出各種各樣的布局。Grid組件一般和子組件GridItem一起使用,Grid列表中的每一個(gè)條目對(duì)應(yīng)一個(gè)GridItem組件。
使用ForEach渲染網(wǎng)格布局
和List組件一樣,Grid組件也可以使用ForEach來渲染多個(gè)列表項(xiàng)GridItem,我們通過下面的這段示例代碼來介紹Grid組件的使用。
@Entry
@Component
struct GridExample {
// 定義一個(gè)長(zhǎng)度為16的數(shù)組
private arr: string[] = new Array(16).fill('').map((_, index) => `item ${index}`);
build() {
Column() {
Grid() {
ForEach(this.arr, (item: string) => {
GridItem() {
Text(item)
.fontSize(16)
.fontColor(Color.White)
.backgroundColor(0x007DFF)
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
}
}, item => item)
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.height(300)
}
.width('100%')
.padding(12)
.backgroundColor(0xF1F3F5)
}
}
示例代碼中創(chuàng)建了16個(gè)GridItem列表項(xiàng)。同時(shí)設(shè)置columnsTemplate的值為'1fr 1fr 1fr 1fr',表示這個(gè)網(wǎng)格為4列,將Grid允許的寬分為4等分,每列占1份;rowsTemplate的值為'1fr 1fr 1fr 1fr',表示這個(gè)網(wǎng)格為4行,將Grid允許的高分為4等分,每行占1份。這樣就構(gòu)成了一個(gè)4行4列的網(wǎng)格列表,然后使用columnsGap設(shè)置列間距為10vp,使用rowsGap設(shè)置行間距也為10vp。示例代碼效果圖如下:
上面構(gòu)建的網(wǎng)格布局使用了固定的行數(shù)和列數(shù),所以構(gòu)建出的網(wǎng)格是不可滾動(dòng)的。然而有時(shí)候因?yàn)閮?nèi)容較多,我們通過滾動(dòng)的方式來顯示更多的內(nèi)容,就需要一個(gè)可以滾動(dòng)的網(wǎng)格布局。我們只需要設(shè)置rowsTemplate和columnsTemplate之間的一個(gè)即可,另一個(gè)不設(shè)置。
如:將示例代碼中GridItem的高度設(shè)置為固定值,例如100;僅設(shè)置columnsTemplate屬性,不設(shè)置rowsTemplate屬性,就可以實(shí)現(xiàn)Grid列表的滾動(dòng):
Grid() {
ForEach(this.arr, (item: string) => {
GridItem() {
Text(item)
.height(100)
...
}
}, item => item)
}
.columnsTemplate('1fr 1fr 1fr 1fr')//將網(wǎng)格分為4行,每行占容器一等份的長(zhǎng)度
.columnsGap(10)//設(shè)置列間距為10vp
.rowsGap(10)//設(shè)置行間距
.height(300)//固定高度
此外,Grid像List一樣也可以使用onScrollIndex來監(jiān)聽列表的滾動(dòng)。
ArkUI-自定義組件
自定義組件聲明
自定義組件大家并不陌生;在ArkUI中,自定義組件的實(shí)現(xiàn)是一個(gè)struct結(jié)構(gòu)體+@Component裝飾器組合,就完成了聲明。
@Component
struct Index3 {
}
使用自定義組件
比如我完成了一個(gè)名為 Header 的自定義組件,那么我在代碼中使用就是 直接使用 Header() 來使用這個(gè)組件:
自定義組件案例:封裝標(biāo)題欄自定義組件
- 首先編寫標(biāo)題欄的item
Row(){
Image($r('app.media.back'))
.width(40)
.height(40)
.interpolation(ImageInterpolation.High)
Text("標(biāo)題")
.fontSize(30)
.fontColor('#000000')
.fontWeight(FontWeight.Bold)
.margin({left:30})
Blank()
Image($r('app.media.refresh'))
.width(40)
.height(40)
}.justifyContent(FlexAlign.Start)
.width("100%")
.alignItems(VerticalAlign.Center)
.padding({left:20,top:20,right:20,bottom:20})
- 創(chuàng)建一個(gè)自定義View:CommonTitleBar
/**
* 標(biāo)題欄組件
*/
@Component
struct CommonTitleBar{
build(){
//..放置寫好的item布局
}
}
- 放置第一步中寫好的item布局代碼
/**
* 標(biāo)題欄組件
*/
@Component
export struct CommonTitleBar{
build(){
Row(){
Image($r('app.media.back'))
.width(40)
.height(40)
.interpolation(ImageInterpolation.High)
Text("標(biāo)題")
.fontSize(30)
.fontColor('#000000')
.fontWeight(FontWeight.Bold)
.margin({left:30})
Blank()
Image($r('app.media.refresh'))
.width(40)
.height(40)
}.justifyContent(FlexAlign.Start)
.width("100%")
.alignItems(VerticalAlign.Center)
.padding({left:20,top:20,right:20,bottom:20})
}
}
- 給自定義View設(shè)置所需的成員參數(shù),并配置構(gòu)造函數(shù),使用。
@State private _title: string = "";
constructor(_title: string) {
super();
this._title = _title
}
....
Text(this._title)
.fontSize(30)
.fontColor('#000000')
.fontWeight(FontWeight.Bold)
.margin({ left: 30 })
....
- 在主頁(yè)使用CommonTitleBar組件
import { CommonTitleBar } from '../widget/CommonTitleBar';//導(dǎo)入組件
build() {
Column() {
CommonTitleBar({_title:'商品列表'})
.margin(10)//所有的自定義組件也是添加樣式函數(shù)
list....
}
}
- 這樣一個(gè)公共的標(biāo)題欄組件就完成了。
自定義構(gòu)建函數(shù)及案例:封裝ListItem布局
接下來我們還想將商品列表的ListItem也進(jìn)行封裝,那么可以繼續(xù)使用自定義組件的方式來封裝;但是,我們還有一種更方便的方法,自定義構(gòu)建函數(shù)。
- 在全局中,使用@Builder來標(biāo)識(shí)自定義構(gòu)建函數(shù),自定義構(gòu)建函數(shù)建議使用大寫字母開頭,因?yàn)樗部梢员焕斫獬梢粋€(gè)匿名的自定義View組件
@Builder function ShopItemCard(){...}
- 在函數(shù)中,完成聲明式UI的聲明:將我們先前寫的ListItem的布局復(fù)制過來。
//全局自定義構(gòu)建函數(shù)
@Builder function ShopItemCard(){
//列表項(xiàng)內(nèi)容,只能包含一個(gè)根組件
//進(jìn)行item布局的繪制
Row({ space: 20 }) {
Image('https://img0.baidu.com/it/u=3628503530,464378779&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=800')
.width(100)
.height(100)
.borderRadius(20)
.interpolation(ImageInterpolation.High)
Column() {
Text(item._name)
.fontSize(20)
.fontColor('#000000')
.fontWeight(FontWeight.Bold)
Text("商品售價(jià):¥" + item._price)
.fontSize(20)
.fontColor('#ff0000')
.fontWeight(FontWeight.Bold)
}.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.SpaceEvenly)
.height(130)
}
.width('95%')
.margin({ top: 15, bottom: 15 })
.padding(15)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Start)
.backgroundColor('#c6c6c6')
.borderRadius(20)
}
- 此時(shí)發(fā)現(xiàn)函數(shù)中 item 報(bào)紅,因?yàn)槟貌坏絠tem數(shù)據(jù),所以增加一個(gè)形參:
@Builder function ShopItemCard(item:ShopItemBean){...}
- 在List組件中,調(diào)用自定義構(gòu)建函數(shù):
List({ space: 10 }) { //列表項(xiàng)的間距
ForEach(this.items, (item: ShopItemBean) => {
ListItem() { //ListItem是標(biāo)記,不是容器。
//此處調(diào)用自定義構(gòu)建函數(shù)
ShopItemCard(item)
}
})
}
- 這樣便完成了ListItem的UI繪制。
局部自定義構(gòu)建函???
我們剛才的實(shí)例中自定義構(gòu)建函數(shù)是聲明在全局的,即全局自定義構(gòu)建函數(shù),這樣的話其他文件也能使用它。
如果只想給將自定義構(gòu)建函數(shù)放在類中去使用,不給外部使用,那么就得使用局部自定義構(gòu)建函數(shù)。即 把函數(shù)的聲明&定義放在class中;但是請(qǐng)注意,在class類中的函數(shù)不可以使用function關(guān)鍵字,所以在class中function關(guān)鍵字是要省略的,即:
class MyClass(){
//局部自定義構(gòu)建函數(shù)
@Builder ShopItemCard(item:ShopItemBean){...}
}
注意:調(diào)用局部自定義構(gòu)建函數(shù)時(shí),添加 this.前綴,因?yàn)轭愔械某蓡T,必須使用this來指向。
自定義公共樣式函數(shù)
自定義公共樣式 與 自定義組件的構(gòu)建函數(shù)大差不差,只是將 @Builder 裝飾器 更換為了 @Styles。
自定義公共樣式函數(shù)主要是封裝公共的樣式,給其他View使用。
定義:如下定義了一個(gè)公共樣式函數(shù),并將width和height設(shè)置為100%
//自定義公共樣式函數(shù)
@Styles function mathStyleWH(){
.width('100%')
.height('100%')
}
使用:直接在組件的尾部調(diào)用我們的mathStyleWH()函數(shù),等于Column組件調(diào)用了width('100%') 和 height('100%')兩個(gè)函數(shù)。這玩意像宏定義。
Column()
.mathStyleWH()
注意:
- 自定義公共樣式函數(shù)也分 全局 和 局部,與自定義構(gòu)建函數(shù)一致。
- 自定義公共樣式函數(shù),默認(rèn)情況下只能修改所有組件的公共函數(shù),即通用的屬性方法。
- 如果需要修改某個(gè)組件的特定屬性,如Text組件的fontsize屬性,那么就需要使用@Extend裝飾器,表示繼承該View。
//指定父類為Text組件,設(shè)置其的特定屬性。
@Extend(Text) function setFontColor(){
.fontColor('#00ff00')
}
總結(jié)
-
- 自定義View
@Component Struct View
- 自定義構(gòu)建函數(shù)
@Builder funName(){...}
自定義構(gòu)建函數(shù)又分為:全局和局部函數(shù),作用域不同。
- 自定義樣式函數(shù):@Styles functionName(){...}
自定義樣式函數(shù)用來集中控制公共樣式,便于后期對(duì)樣式統(tǒng)一的修改。
@Styles裝飾器只能修改所有組件公共的屬性,如果想使用特定組件的專用屬性,可以使用@Extend()繼承。
@Styles 裝飾器 支持修飾全局和局部函數(shù),而@Extend 裝飾器只允許修飾全局函數(shù)。
|