應(yīng)用場(chǎng)景:
智能汽車是集環(huán)境感知,、規(guī)劃決策、多等級(jí)輔助駕駛等功能于一體的智能網(wǎng)聯(lián)綜合系統(tǒng),,它集中運(yùn)用了計(jì)算機(jī),、現(xiàn)代傳感、信息融合,、通訊,、人工智能及自動(dòng)控制等技術(shù),是典型的高新技術(shù)綜合體,。簡(jiǎn)單的說,,智能汽車的出現(xiàn)將逐步放松車,、手,、眼,,讓開車,,用車變得簡(jiǎn)單。這樣的產(chǎn)品對(duì)有本兒不敢上路的人來說或許是大大的福音,。
在北方冬天有點(diǎn)冷,,這個(gè)時(shí)候,,去車?yán)铮瑴囟群艿?,給人一種不舒服的感覺,,那么有沒有一種可能,就是可以通過手機(jī)App,,實(shí)現(xiàn)對(duì)車內(nèi)的一些情況的監(jiān)測(cè),,答案是有的,今天做的這個(gè)App,,就是這樣一個(gè)App,。
我要實(shí)現(xiàn)的功能主要有
在開始之前大家可以先預(yù)覽一下我完成之后的效果,。如下圖所示:
是不是很炫酷呢?
搭建OpenHarmony環(huán)境
完成本篇Codelab我們首先要完成開發(fā)環(huán)境的搭建,,本示例以DaYu200開發(fā)板為例,參照以下步驟進(jìn)行:
獲取OpenHarmony系統(tǒng)版本:標(biāo)準(zhǔn)系統(tǒng)解決方案(二進(jìn)制)
以3.0版本為例:
- 開始前請(qǐng)參考工具準(zhǔn)備 ,完成DevEco Studio的安裝和開發(fā)環(huán)境配置,。
- 開發(fā)環(huán)境配置完成后,,請(qǐng)參考使用工程向?qū)?創(chuàng)建工程(模板選擇“Empty Ability”),選擇eTS語言開發(fā),。
- 工程創(chuàng)建完成后,選擇使用真機(jī)進(jìn)行調(diào)測(cè) ,。
相關(guān)概念
容器組件
基礎(chǔ)組件
通用
TS語法糖
好的接下來我將詳細(xì)講解如何制作
開發(fā)教學(xué)
創(chuàng)建好的 eTS工程目錄
新建工程的ETS目錄如下圖所示,。
各個(gè)文件夾和文件的作用:
- index.ets:用于描述UI布局,、樣式、事件交互和頁(yè)面邏輯,。
- app.ets:用于全局應(yīng)用邏輯和應(yīng)用生命周期管理。
接下來開始正文,。
我們的主要操作都是在在pages目錄中,然后我將用不到10分鐘的時(shí)間,,帶大家實(shí)現(xiàn)這個(gè)功能,。
拆解
根據(jù)設(shè)計(jì)圖,我們可以分為內(nèi)容展示區(qū)和菜單,。
針對(duì)這一點(diǎn),,我們可以用Navigation組件作為Page頁(yè)面的根容器,,通過屬性設(shè)置來展示頁(yè)面的標(biāo)題,、工具欄、菜單,。
Navigation() {
Column({ space: 20 }) {
if (this.index == 0)
DoorLook()
else if (this.index == 1)
Battery()
else if (this.index == 2)
Temp()
else if (this.index == 3)
Tyre()
}
.backgroundColor(Color.Black)
.justifyContent(FlexAlign.SpaceAround)
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.size({ width: '100%', height: '100%' })
} .size({ width: '100%', height: '100%' })
.toolBar(this.toolbarWidget())
.hideToolBar(this.hideToolBar)
.hideTitleBar(this.hideTitleBar)
具體布局
具體布局設(shè)計(jì)到一些細(xì)節(jié)的地方,例如間隔,,邊框,,當(dāng)前組件尺寸設(shè)置等一些特殊情況,基本上就是嵌套,,一層一層去實(shí)現(xiàn)。
代碼結(jié)構(gòu)
編碼
Index.ets
import Tyre from './tyre_page';
import Temp from './temp_page';
import Battery from './battery_page';
import DoorLook from './door_lock_page';
@Entry
@Component
struct ComponentTest {
@State index: number = 0; // 選項(xiàng)卡下標(biāo),,默認(rèn)為第一個(gè)
@State hideToolBar: boolean = false;
@State hideTitleBar: boolean = true;
private imageArray: string[] = ['app.media.Lock', 'app.media.Charge', 'app.media.Temp', 'app.media.Tyre',]; // 數(shù)據(jù)源
@Builder toolbarWidget() { // 通過builder自定義toolbar
Row() {
Column() {
Image( this.index==0?$r('app.media.lock'):$r('app.media.lock0') )
.size({ width: 36, height: 36 }).margin({ bottom: 4, top: 12 })
}
.alignItems(HorizontalAlign.Center)
.height('100%')
.layoutWeight(1)
.onClick(() => {
this.index = 0;
})
Column() {
Image(this.index==1?$r('app.media.battery'): $r("app.media.battery0"))
.size({ width: 36, height: 36 }).margin({ bottom: 4, top: 12 })
}
.alignItems(HorizontalAlign.Center)
.height('100%')
.layoutWeight(1)
.onClick(() => {
this.index = 1;
})
Column() {
Image(this.index==2?$r('app.media.yytemp'): $r('app.media.yytem0'))
.size({ width: 36, height: 36 }).margin({ bottom: 4, top: 12 })
}
.alignItems(HorizontalAlign.Center)
.height('100%')
.layoutWeight(1)
.onClick(() => {
this.index = 2;
})
Column() {
Image( this.index==3?$r('app.media.tyre'): $r('app.media.tyre0'))
.size({ width: 36, height: 36 }).margin({ bottom: 4, top: 12 })
}
.alignItems(HorizontalAlign.Center)
.height('100%')
.layoutWeight(1)
.onClick(() => {
this.index = 3;
})
}.backgroundColor(Color.Black)
.width('100%')
.height(66)
}
build() {
Navigation() {
Column({ space: 20 }) {
//根據(jù)索引展示對(duì)應(yīng)內(nèi)容?
if (this.index == 0)
DoorLook()
else if (this.index == 1)
Battery()
else if (this.index == 2)
Temp()
else if (this.index == 3)
Tyre()
}
.backgroundColor(Color.Black)
.justifyContent(FlexAlign.SpaceAround)
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.size({ width: '100%', height: '100%' })
}
.size({ width: '100%', height: '100%' })
.title("跟著堅(jiān)果學(xué)OpenHarmony")
.toolBar(this.toolbarWidget())//自定義底部菜單欄
.hideToolBar(this.hideToolBar)
.hideTitleBar(this.hideTitleBar)
.menus([
{
value: "關(guān)",
icon: 'common/images/door_lock.svg',
action: () => {
console.log("工具欄")
}
},
{
value: "開",
icon: 'common/images/door_unlock.svg',
action: () => {
}
}
])
}
}
效果演示:
車鎖頁(yè)
@Entry
@Component
export default struct DoorLook {
//車鎖頁(yè)
@State isRightDoorLock: boolean = false;
@State isLeftDoorLock: boolean = false;
@State isBonnetLock: boolean = false;
@State isTrunkLock: boolean = false;
build() {
Column() {
Stack() {
Image($r("app.media.Car"))
.width("100%")
.height("100%")
.objectFit(ImageFit.Contain)
.margin({ left: 20 })
Image($r("app.media.door_lock"))
.width(60).height(60).position({ x: 340, y: 50 })
.onClick(() => {
})
Image($r("app.media.door_unlock")).width(60).height(60).position({ x: 50, y: 600 })
Image($r("app.media.door_unlock")).width(60).height(60).position({ x: 640, y: 600 })
Image($r("app.media.door_unlock")).width(60).height(60).position({ x: 340, y: 920 })
}
.backgroundColor(Color.Black)
.width("100%")
.height("100%")
}
}
}
效果演示:
電池頁(yè)
@Entry
@Component
export default struct Battery {
//電池頁(yè)
build() {
Column() {
Stack() {
Image($r("app.media.Car"))
.width("100%")
.height("80%")
.objectFit(ImageFit.Contain)
.margin({ left: 20, top: 150, bottom: 300 })
Text("220 mi").fontColor(Color.White).fontWeight(FontWeight.Bold).fontSize(79).position({ x: 260, y: 20 })
Text("62 %").fontColor(Color.White).fontWeight(FontWeight.Bold).fontSize(60).position({ x: 320, y: 90 })
Text("22 mi /hr").fontColor(Color.White).fontWeight(FontWeight.Bold).fontSize(45).position({ x: 20, y: 1000 })
Text("232 v").fontColor(Color.White).fontWeight(FontWeight.Bold).fontSize(45).position({ x: 550, y: 1000 })
}
.backgroundColor(Color.Black)
.width("100%")
.height("100%")
}
}
}
效果演示:
空調(diào)頁(yè)
@Entry
@Component
export default struct Temp {
//空調(diào)頁(yè)
build() {
Column() {
Stack() {
Image($r("app.media.Car"))
.width("100%")
.height("100%")
.objectFit(ImageFit.Contain)
.position({ x: 268, y: 90 })
.margin({ left: 20 })
Image($r("app.media.Hot_glow_4"))
.width("90%")
.height("90%")
.objectFit(ImageFit.Contain)
.position({ x: 220, y: 90 })
.margin({ left: 20 })
Text("29" + "\u2103",).fontSize(90).fontColor(Color.Orange).position({ x: 90, y: 400 })
Image($r("app.media.arrow_drop_up"))
.width(60)
.height(60)
.position({ x: 120, y: 360 })
Image($r("app.media.arrow_drop_down"))
.width(60)
.height(60)
.position({ x: 120, y: 480 })
Image($r("app.media.cool")).width(60).height(60).position({ x: 20, y: 40 })
Image($r("app.media.heating"))
.width(60)
.height(60)
.position({ x: 80, y: 90 })
.borderRadius(7)
.margin({ right: 40 })
Column() {
Text("當(dāng)前溫度").fontSize(32).fontColor(Color.White).margin({ bottom: 20 })
Row({ space: 30 }) {
Column() {
Text("里面").fontSize(32).fontColor(Color.Orange)
Text("20" + "\u2103",).fontSize(32).fontColor(Color.White)
}
Column() {
Text("外邊").fontSize(32).fontColor(Color.Yellow)
Text("35" + "\u2103",).fontSize(32).fontColor(Color.White)
}
}
}.position({ x: 20, y: 800 })
}
.backgroundColor(Color.Black)
.offset({
y: -20
})
.width("100%")
.height("100%")
}
}
}
效果演示:
輪胎頁(yè)
import { TyrePsiCard } from './tyre_psi_card'
@Entry
@Component
export default struct Tyre {
//輪胎頁(yè)
build() {
Column() {
Stack() {
Image($r("app.media.Car"))
.width("100%")
.height("80%")
.objectFit(ImageFit.Contain)
.margin({ left: 20 })
Image($r("app.media.FL_Tyre"))
.width("10%")
.height("10%")
.objectFit(ImageFit.Contain)
.position({ x: 180, y: 700 })
Image($r("app.media.FL_Tyre"))
.width("10%")
.height("10%")
.objectFit(ImageFit.Contain)
.position({ x: 500, y: 700 })
Image($r("app.media.FL_Tyre"))
.width("10%")
.height("10%")
.objectFit(ImageFit.Contain)
.position({ x: 500, y: 260 })
Image($r("app.media.FL_Tyre"))
.width("10%")
.height("10%")
.objectFit(ImageFit.Contain)
.position({ x: 180, y: 260 })
TyrePsiCard({ x: 60, y: 60, boardColor: Color.Blue })
TyrePsiCard({ x: 380, y: 60, boardColor: Color.Blue })
TyrePsiCard({ x: 60, y: 500, boardColor: Color.Blue, isBottomTwoTyre: false })
TyrePsiCard({ x: 380, y: 500, isBottomTwoTyre: false })
}
.backgroundColor(Color.Black)
.width("100%")
.height("100%")
}
}
}
效果演示:
輪胎參數(shù)
/**
* 輪胎詳細(xì)信息
*/
@Entry
@Component
export struct TyrePsiCard {
private text: string = ''
private x: number = 0
private y: number = 0
private boardColor: Color = Color.Red
private isBottomTwoTyre: boolean = true;
build() {
Column() {
if (this.isBottomTwoTyre) {
Text("23.6psi",).fontSize(60)
.fontColor(Color.White).margin({ right: 60 })
Text("56.0\u2103").fontSize(36)
.fontColor(Color.Orange).margin({ bottom: 70 })
Text("Low").fontSize(60)
.fontColor(Color.White)
Text("Pressure").fontSize(36)
.fontColor(Color.White)
} else {
Text("Low").fontSize(60).margin({ right: 60 })
.fontColor(Color.White)
Text("Pressure").fontSize(36)
.fontColor(Color.White).margin({ bottom: 70 })
Text("23.6psi",).fontSize(60)
.fontColor(Color.White)
Text("56.0\u2103").fontSize(36)
.fontColor(Color.Orange)
}
}
.border({
width: 3,
color: this.boardColor
})
.width(280)
.justifyContent(FlexAlign.Start)
.alignItems(HorizontalAlign.Start)
// .padding({ left: 10, bottom: 20, top: 20 })
.position({ x: this.x, y: this.y })
}
}
效果演示:
恭喜你
在本文中,,通過實(shí)現(xiàn)智聯(lián)汽車App示例,我主要為大家講解了如下ArkUI(基于TS擴(kuò)展的類Web開發(fā)范式)組件
希望通過本教程,各位開發(fā)者可以對(duì)以上基礎(chǔ)組件具有更深刻的認(rèn)識(shí),。
后面的計(jì)劃: