第三篇 - ArkUI布局基礎(chǔ)與制作可交互頁面
導(dǎo)讀:在本篇文章里敌厘,您將掌握事件、裝飾器森渐、雙向綁定等相關(guān)知識(shí)类腮,并利用所學(xué)知識(shí)做一個(gè)待辦列表的案例臊泰。
練手案例:登錄界面
開始之前,先說些題外話
貓林老師發(fā)現(xiàn)不少同學(xué)可以獨(dú)立寫出來蚜枢,我很欣慰缸逃。說明行動(dòng)力、悟性厂抽、之前前端留下的布局思想都還在需频。希望各位同學(xué)和更多的朋友們都能參與進(jìn)來。大家以后寫完可以把自己的代碼或者效果貼到評(píng)論區(qū)相互討論修肠。討論的人越多越有學(xué)習(xí)氛圍贺辰,在這里大家都可以找到志同道合的人。并且嵌施,每一次熱烈的討論都能激勵(lì)貓林老師更認(rèn)真迅速地去寫下一篇文章饲化。
而且寫教程文真的很需要花費(fèi)額外時(shí)間,那就會(huì)擠占貓林老師想做愛做的事的時(shí)間??吗伤。而且純愛心發(fā)電其實(shí)動(dòng)力并不足吃靠,所以也真的很需要各位讀者提供熱烈的正向回饋來激勵(lì)貓林老師,所以大家請(qǐng)一定要多點(diǎn)贊足淆、收藏巢块、評(píng)論。要是可以巧号,也分享給你周圍想學(xué)鴻蒙的朋友族奢。貓林老師保證把系列文章更新下去,讓大家從文章里就能學(xué)到真東西丹鸿,并且具備找工作能力越走。
-
好了,話不多說靠欢,開始說回上次的作業(yè)案例廊敌,讓我們先回顧一下作業(yè)的效果圖:
從上圖分析可以發(fā)現(xiàn)整體上所有內(nèi)容是從上往下布局,所以用Column作為根容器非常合適门怪。
-
然后里面可以分為8行元素骡澈,分別為:Image、Text掷空、Text肋殴、TextInput囤锉、TextInput、Row护锤、Button嚼锄、Text,如圖
這些都是比較容易看出來的布局蔽豺,主要是給大家解釋下
短信驗(yàn)證碼登錄
和忘記密碼
那一行,為什么還要用一個(gè)Row
包起來呢拧粪?因?yàn)槿绻@兩個(gè)文字不被Row包起來的話修陡,那么父組件是Column,那短信驗(yàn)證碼登錄
和忘記密碼
就會(huì)變成一行一個(gè)可霎。所以用一個(gè)Row
包起來魄鸦,因?yàn)镽ow有從左到右布局子組件的能力,而這兩個(gè)文字就需要從左到右癣朗,只不過一個(gè)在起點(diǎn)拾因,一個(gè)在終點(diǎn)(即在首尾),所以這里到時(shí)候還可以給它做一個(gè)主軸上的布局為SpaceBetween
旷余。其他的無非記得要讓根容器
Column
鋪滿屏幕绢记,也即寬高百分百,圖片給寬度正卧、登錄界面
給文字大小和加粗蠢熄,登錄帳號(hào)以使用更多服務(wù)
改文字顏色、文字大小炉旷。兩個(gè)TextInput
給占位符签孔,其中第二個(gè)TextInput
記得要把type設(shè)置為password。其他剩余的三個(gè)label都是改文字顏色窘行、字體大小饥追。登錄按鈕給寬度鋪滿。然后整個(gè)頁面是灰色罐盔,所以給Column設(shè)置背景色但绕,再給TextInput
設(shè)置背景色為白色。-
根據(jù)上述分析翘骂,代碼如下
Column() { Image($r('app.media.app_icon')) .width(100) Text('登錄界面') .fontSize(24) .fontWeight(700) Text('登錄賬號(hào)以使用更多服務(wù)') .fontColor(Color.Gray) .fontSize(14) TextInput({ placeholder: '賬號(hào)' }) .backgroundColor('#fefefe') TextInput({ placeholder: '密碼' }) .backgroundColor('#fefefe') .type(InputType.Password) Row() { Text('短信驗(yàn)證碼登錄') .fontColor('#3172f3') Text('忘記密碼') .fontColor('#3172f3') } .justifyContent(FlexAlign.SpaceBetween) Button('登錄') .width('100%') Text('注冊(cè)賬號(hào)') .fontColor('#3172f3') } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) .backgroundColor('#eff1f3')
對(duì)應(yīng)效果如下:
-
此時(shí)大家發(fā)現(xiàn)兩個(gè)問題:
- 明明
短信驗(yàn)證碼
那一行的Row
給了justifyContent(FlexAlign.SpaceBetween)
壁熄,但沒生效,看著還是居中碳竟。為什么呢草丧? - 所有內(nèi)容行與行之間沒有間距,導(dǎo)致挨的太緊莹桅。
- 明明
-
這兩個(gè)問題都很好很解決昌执,分別如下
-
給了
FlexAlign.SpaceBetween
也沒生效烛亦,是因?yàn)樨埩掷蠋熒瞎?jié)課就說過大部分組件不給寬高就是靠?jī)?nèi)容撐開寬高,也即內(nèi)容有大懂拾,Row就只有多大煤禽。所以你設(shè)置首尾對(duì)齊實(shí)際上它已經(jīng)是首尾了,只不過因?yàn)镽ow就那么大岖赋,所以效果不動(dòng)
所以解決辦法很簡(jiǎn)單:給Row一個(gè)width('100%')
即可 行與行之間要設(shè)置間距可以給Column加
space
-
-
因此檬果,改良代碼如下(僅寫出本次改動(dòng)部分)
Column({ space: 10 }) { ...... Row() { Text('短信驗(yàn)證碼登錄') .fontColor('#3172f3') Text('忘記密碼') .fontColor('#3172f3') } .width('100%') .justifyContent(FlexAlign.SpaceBetween) ........ } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) .backgroundColor('#eff1f3')
-
此時(shí)效果如下
-
發(fā)現(xiàn)間距是有了,但是中間的賬號(hào)唐断、密碼选脊、短信驗(yàn)證碼登錄這歌區(qū)域跟上面和下面太近,需要把這部分跟上下加一些間距
-
如上圖所示脸甘,發(fā)現(xiàn)這個(gè)時(shí)候我們應(yīng)該把中間這一部分作為一個(gè)整體恳啥,再統(tǒng)一設(shè)置整體的上下外間距即可。因此需要給中間的2個(gè)
TextInput
和它下面包住兩個(gè)文字的Row
再套一個(gè)父容器丹诀。這里請(qǐng)大家思考下钝的,他們的父容器,用Column
好還是Row
好呢铆遭?- 沒錯(cuò)硝桩,用
Column
好!因?yàn)橛?code>Row他們會(huì)從左往右排列疚脐,而我們依然要它從上到下亿柑,只不過多個(gè)父容器而已,所以用Column
- 沒錯(cuò)硝桩,用
-
那分析完加父容器后棍弄,還有個(gè)問題望薄。怎么設(shè)置這個(gè)父容器的距離外部的間距呢?會(huì)
css
的同學(xué)知道呼畸,是margin
痕支,沒錯(cuò),ArkTS
里也是margin
(如果不懂什么叫margin的請(qǐng)?zhí)魬?zhàn)到本文最后的附錄:外間距與內(nèi)間距蛮原,再回此繼續(xù)觀看)卧须,語法如下組件() { } .margin(間距數(shù)) // 例 Column() { } .margin(20) // 代表這個(gè) Column 具體上下左右間距都是20
-
如果你不需要上下左右間距都是同一個(gè)值,則可以傳入一個(gè)對(duì)象儒陨,分別設(shè)置不同的margin花嘶,例
Column() { } .margin({ left: 20, right: 10, top: 15, bottom: 30 } ) // 代表這個(gè)Column左間距20,右間距10蹦漠,上間距15椭员,下間距30
-
也可以僅設(shè)置幾個(gè)方向的間距,沒設(shè)置方向的間距代表為0笛园,例
Column() { } .margin({ top: 10, bottom: 20 } ) // 代表這個(gè)Column上間距10隘击,下間距20侍芝,左右間距因?yàn)闆]設(shè)置,那么則代表0也即沒有間距
-
因此埋同,案例代碼里先給中間部分加
Column
州叠,且設(shè)置外間距。并且因?yàn)橹虚g部分包了Colum后凶赁,他們各自之間也沒間距了咧栗,因此給包住驗(yàn)證碼登錄
文字的Row再加一個(gè)上間距,TextInput不用加虱肄,因?yàn)樗麄儽旧砭鸵ぴ谝黄鹇ハǎ膭?dòng)代碼如下Column({ space: 10 }) { ......... Column() { TextInput({ placeholder: '賬號(hào)' }) .backgroundColor('#fefefe') TextInput({ placeholder: '密碼' }) .backgroundColor('#fefefe') .type(InputType.Password) Row() { Text('短信驗(yàn)證碼登錄') .fontColor('#3172f3') Text('忘記密碼') .fontColor('#3172f3') } .margin({ top: 10 }) } .margin({ top: 20, bottom: 20 }) ....... }
-
此時(shí)效果如下
-
沒錯(cuò),現(xiàn)在跟最終效果圖已經(jīng)差不多了浩峡,但是發(fā)現(xiàn)左右兩邊都挨到邊邊了,而效果圖需要左右兩邊都有點(diǎn)間距错敢。這時(shí)候有兩種解決辦法:
- 給兩個(gè)TextInput翰灾、Row、Button這四行設(shè)置左右外間距
- 給他們共同的父組件設(shè)置內(nèi)間距
-
很明顯稚茅,用第二種給共同的父組件設(shè)置內(nèi)間距辦法更方便纸淮。但是ArkTS里如何設(shè)置呢?其實(shí)還是用
padding
亚享,并且用法跟margin
是一樣的咽块,例Column() { } .padding(20) // 上下左右四個(gè)方向內(nèi)間距都是20 Column() { } .padding({ top: 20, bottom: 10, left: 20, right: 25 }) // 上內(nèi)間距20,下內(nèi)間距10欺税,左內(nèi)間距20侈沪,右內(nèi)間距25 Column() { } .padding({ left: 20, right: 20 }) // 左內(nèi)間距和右內(nèi)間距都是20,上下沒寫則默認(rèn)是0
-
因此晚凿,再給根組件
Column
設(shè)置padding亭罪,且只需要左右間距即可Column({ space: 10 }) { ........ } ....... .padding({ left: 10, right: 10 })
至此,一個(gè)完整的
登錄界面
就寫完了歼秽,你學(xué)廢了嗎应役?
- 本案例新知識(shí):
- margin: 外間距
- padding :內(nèi)間距
事件
上面的登錄案例中,我們目前點(diǎn)
登錄按鈕
是沒有任何反應(yīng)的燥筷。要想讓它有反應(yīng)箩祥,必須添加事件,在ArkTS中如何添加事件呢肆氓?-
語法
組件() { } .on事件名( e => { // 事件處理代碼 } )
-
例
Button('登錄') .onClick(e => { // 處理代碼 })
注意:上面的Click里的C大寫袍祖。后面的事件名如無特殊情況,都是要首字母大寫做院,例如change事件盲泛,寫的時(shí)候要加
onChange
濒持,這跟前端里的全小寫不一樣,大家要注意寺滚。-
e則是事件對(duì)象柑营,但用的略少,不需要時(shí)村视,可以不寫e官套,替換為小括號(hào)
Button('登錄') .onClick(() => { // 處理代碼 })
提示框
如果現(xiàn)在,我希望點(diǎn)擊按鈕后彈出
登錄成功
的提示框怎么辦呢蚁孔?ArkUI
里提供了PromptAction
對(duì)象奶赔,專門用來做彈窗-
用法:
- 先導(dǎo)入,再調(diào)用
PromptAction
對(duì)象的showToast
方法杠氢,傳入對(duì)象站刑,配置提示信息,例
import { promptAction } from '@kit.ArkUI' promptAction.showToast({ message: '提示消息', // 提示的文字 duration: 2000 // 顯示時(shí)長(zhǎng)鼻百,不填則默認(rèn)為1500 });
- 先導(dǎo)入,再調(diào)用
技巧:可以在寫代碼時(shí)绞旅,直接寫promptAction,然后出提示后按回車温艇,DevEco會(huì)自動(dòng)幫你生成導(dǎo)入的代碼因悲,如下圖
- 注意:
- duration為提示框多久后消失(也即顯示時(shí)長(zhǎng)),可以不填勺爱,不填則默認(rèn)為1500晃琳,并且最小值也是1500,最大值是10000琐鲁。如果填寫的數(shù)字小于1500卫旱,也按1500來顯示,如果大于10000围段,也按10000來顯示誊涯。
- 單位是毫秒,1500即1.5秒
-
例:
promptAction.showToast({ message: '貓林老師教程真好蒜撮!' })
- 效果如下
- 更多彈窗的用法可閱讀官方文檔:點(diǎn)我跳轉(zhuǎn)至官方文檔
聲明組件內(nèi)成員變量
很多時(shí)候我們這個(gè)頁面(組件)需要聲明一些變量用來保存數(shù)據(jù)暴构,和對(duì)其處理。那么怎么聲明呢段磨?
-
一般會(huì)寫在
build
函數(shù)的上面取逾,struct
關(guān)鍵子下面,即下圖位置
-
語法為:
變量名: 類型 = 初始值
-
例:
userId: string = '' // 聲明了一個(gè)名為 userId 的變量苹支,它是字符串類型砾隅,初始值為空字符串
-
變量聲明好了,如何在代碼中使用呢债蜜?一律前面加this訪問晴埂,例
this.userId
雙向綁定
-
學(xué)會(huì)聲明成員變量后究反,我們?cè)?code>登錄案例 里,聲明兩個(gè)變量儒洛,分別叫
userId
與userPwd
精耐,專門用來跟賬號(hào)、密碼輸入框分別做雙向綁定struct Index { // 成員變量列表 userId: string = 'admin' userPwd: string = '123' build() { ........ } }
插播雙向綁定: 即數(shù)據(jù)一旦改變琅锻,界面跟著變卦停。 界面輸入內(nèi)容有變化,數(shù)據(jù)也跟著變恼蓬。
-
那么
ArkTS
里如何讓數(shù)據(jù)跟輸入框做雙向綁定呢惊完?(Next版本后新增的語法)TextInput({ text: $$成員變量 }) // 例 TextInput( text: $$this.userId )
-
接下來讓我們把聲明的
userId
與userPwd
分別綁定到賬號(hào)框和密碼框TextInput({ placeholder: '賬號(hào)', text: $$this.userId }) .backgroundColor('#fefefe') TextInput({ placeholder: '密碼', text: $$this.userPwd }) .backgroundColor('#fefefe') .type(InputType.Password)
-
此時(shí)保存代碼會(huì)看到預(yù)覽器里界面已經(jīng)能顯示綁定的數(shù)據(jù)了,如圖
-
那我們說雙向綁定是:數(shù)據(jù) -> 界面处硬, 同樣小槐,界面的輸入變化也會(huì)影響數(shù)據(jù),那是否能呢荷辕?帶著這個(gè)疑問本股,我們先給
登錄
按鈕加一個(gè)點(diǎn)擊事件,點(diǎn)擊事件里用console.log
輸出這兩個(gè)變量的值桐腌。Button('登錄') .width('100%') .onClick(() => { console.log(`賬號(hào):${this.userId}, 密碼:${this.userPwd}`) })
注意:這里用到了模板字符串,一些同學(xué)可能不太理解這種字符串苟径。這里說明一下:首先是用`這個(gè)符號(hào)包起來案站,跟單引號(hào)雙引號(hào)都表示字符串,但區(qū)別在于模板字符串能很方便做字符串拼接棘街,例如上面的代碼蟆盐,相當(dāng)于是 '賬號(hào):' + this.userId + '密碼:' + this.userPwd
-
然后我們?nèi)ヮA(yù)覽起的界面上重新輸入,再點(diǎn)按鈕輸出遭殉,看顯示什么(具體看截圖石挂,可以看到在哪看console.log輸出的內(nèi)容)
-
小結(jié):
- 在輸入框里,使用成員變量前加
$$
即可雙向綁定
- 在輸入框里,使用成員變量前加
-
需注意:
- 目前
$$
僅能用在基本數(shù)據(jù)類型且綁定給內(nèi)置組件
- 目前
裝飾器 - @State
從上面的效果可以看到险污,已經(jīng)實(shí)現(xiàn)了雙向綁定痹愚,但此時(shí)存在一個(gè)問題:數(shù)據(jù)無法再觸發(fā)界面更新
-
例:修改登錄的點(diǎn)擊事件,在里面我修改
userId
的值蛔糯,看界面是否能更新Button('登錄') .width('100%') .onClick(() => { this.userId = '我要變' console.log('新值:' + this.userId) })
-
結(jié)果如圖
-
原因:默認(rèn)聲明的成員變量不具備數(shù)據(jù)改變觸發(fā)界面更新渲染的功能
解決辦法:需要使用裝飾器
-
裝飾器:
修飾某些數(shù)據(jù)拯腮、函數(shù),使其具有特殊作用
裝飾器有很多種蚁飒,本次學(xué)的叫
@State
动壤,注意首字母大寫-
@State作用:
- 當(dāng)被@State修飾的變量數(shù)據(jù)改變時(shí),UI會(huì)發(fā)生對(duì)應(yīng)的重新渲染淮逻。
-
用法
@State 變量: 類型 = '初始值'
-
讓我們測(cè)試一下琼懊,來到
登錄案例
里找到userId
阁簸,給它加@State
試試@State userId: string = 'admin'
-
效果如下圖:
但是同樣的,加了裝飾器后會(huì)有輕微的性能開銷哼丈,即使這種開銷甚至可以忽略不計(jì)启妹。但是對(duì)于對(duì)性能優(yōu)化有要求的
App
而言,則建議削祈。如果數(shù)據(jù)僅僅只是用來內(nèi)部參與運(yùn)算或臨時(shí)接收界面輸入翅溺,不需要將來重新更新UI,就不加@State
裝飾器不光只有
@State
髓抑,后續(xù)還有很多咙崎,學(xué)一個(gè)記一個(gè)。
- 小結(jié):
- 裝飾器
- 修飾數(shù)據(jù)吨拍、函數(shù)等褪猛,使其具有特殊作用
- @State
- 被@State修飾的變量能當(dāng)它數(shù)據(jù)改變時(shí),UI會(huì)發(fā)生對(duì)應(yīng)的重新渲染
- 裝飾器
實(shí)現(xiàn)登錄功能
最后羹饰,我們給
登錄
案例收個(gè)尾伊滋,當(dāng)用戶點(diǎn)擊登錄按鈕時(shí),如果輸入的賬號(hào)是admin
队秩,密碼是123
笑旺,則提示登錄成功,否則登錄失斺勺省(將來學(xué)發(fā)送請(qǐng)求筒主,如今暫時(shí)寫死硬判斷)-
代碼如下
Button('登錄') .width('100%') .onClick(() => { if (this.userId === 'admin' && this.userPwd === '123') { promptAction.showToast({ message: '登錄成功' }) } else { promptAction.showToast({ message: '賬號(hào)或密碼錯(cuò)誤' }) } })
-
效果如圖:
總結(jié)內(nèi)容
本文中我們學(xué)了事件、提示框鸟蟹、成員變量聲明乌妙、雙向綁定、裝飾器建钥。我們回顧一下
-
事件:
- on事件名藤韵,事件名首字母大寫,例如:onClick熊经、onChange
-
提示框:
-
需要先導(dǎo)入
import { promptAction } from '@kit.ArkUI'
-
然后使用
promptAction.showToast( { message: '提示信息'泽艘, duration:時(shí)長(zhǎng) } )
技巧:可以直接輸入promptAction,出提示后镐依,按回車悉盆,DevEco會(huì)自動(dòng)導(dǎo)入
-
-
聲明成員變量
變量: 類型 = 初始值
默認(rèn)情況下,變量改變不會(huì)觸發(fā)界面重新渲染馋吗,因此需要裝飾器:@State
-
雙向綁定
$$this.變量名
課后練習(xí)
- 判斷題:請(qǐng)回答對(duì)或者錯(cuò)
promptAction.showToast方法焕盟,傳入duration屬性,值為1000,代表提示框在1秒后消失
成員變量與輸入框雙向綁定時(shí)脚翘,成員變量前面不用加this
數(shù)據(jù)如果不加@State灼卢,就不能進(jìn)行計(jì)算
練習(xí)答案
-
錯(cuò) 2. 錯(cuò) 3. 錯(cuò)
(錯(cuò)錯(cuò)錯(cuò),是我的錯(cuò)来农。熱戀的時(shí)候怎么不說鞋真,生活的無奈我已好困惑,你能不能不要再啰嗦)--- 請(qǐng)唱出來
附加練習(xí)
- 如上圖所示沃于,做一個(gè)年度待辦目標(biāo)的列表涩咖。
- 本案例功能比較豐富,各位能做多少做多少繁莹。本案例也會(huì)貫穿后面好幾天的教學(xué)檩互,所以涉及非常多新知識(shí),做不出來也正常咨演。
- 提示:打勾部份可以用Image也可以用
Checkbox
闸昨,如需要做出布局,需要自行根據(jù)文檔預(yù)習(xí)Progress
薄风、Stack
饵较、List
等
互動(dòng)環(huán)節(jié)
- 你覺得鴻蒙開發(fā)跟你以前會(huì)的開發(fā),區(qū)別大嗎遭赂?歡迎留下你的觀點(diǎn)循诉。
- 最后,創(chuàng)作不易撇他,請(qǐng)不要吝嗇您的點(diǎn)贊茄猫、關(guān)注、收藏逆粹、轉(zhuǎn)發(fā)!