介紹
本課程使用聲明式語法和組件化基礎知識,搭建一個可刷新的排行榜頁面。在排行榜頁面中,使用循環渲染控制語法來實現列表數據渲染,使用@Builder創建排行列表布局內容,使用裝飾器@State、@Prop、@Link來管理組件狀態。最后我們點擊系統返回按鍵,來學習自定義組件生命周期函數。效果如圖所示:
相關概念
1.渲染控制語法:
- [條件渲染]:使用if/else進行條件渲染。語法如下:
Column() {
if (this.count > 0) {
Text('count is positive')
}
}
ForEach(
arr: any[], // 用于迭代的數組
itemGenerator: (item: any, index?: number) = > void, // 生成子組件的lambda函數
keyGenerator?: (item: any, index?: number) = > string // 用于給定數組項生成唯一且穩定的鍵值
)
2.組件狀態管理裝飾器和@Builder裝飾器:
組件狀態管理裝飾器用來管理組件中的狀態,它們分別是:@State、@Prop、@Link。
- [@State]裝飾的變量是組件內部的狀態數據,當這些狀態數據被修改時,將會調用所在組件的build方法進行UI刷新。
- [@Prop]與@State有相同的語義,但初始化方式不同。@Prop裝飾的變量必須使用其父組件提供的@State變量進行初始化,允許組件內部修改@Prop變量,但更改不會通知給父組件,即@Prop屬于單向數據綁定。
- [@Link]裝飾的變量可以和父組件的@State變量建立雙向數據綁定,需要注意的是:@Link變量不能在組件內部進行初始化。
- [@Builder]裝飾的方法用于定義組件的聲明式UI描述,在一個自定義組件內快速生成多個布局內容。
@State、@Prop、@Link三者關系如圖所示:
3.組件生命周期函數:
[自定義組件的生命周期函數]用于通知用戶該自定義組件的生命周期,這些回調函數是私有的,在運行時由開發框架在特定的時間進行調用,不能從應用程序中手動調用這些回調函數。 右圖是自定義組件生命周期的簡化圖示:
說明: 需要注意的是,部分生命周期回調函數僅對**@Entry**修飾的自定義組件生效,它們分別是:onPageShow、onPageHide、onBackPress。
環境搭建
軟件要求
- [DevEco Studio]版本:DevEco Studio 3.1 Release。
- OpenHarmony SDK版本:API version 9。
硬件要求
- 開發板類型:[潤和RK3568開發板]。
- OpenHarmony系統:3.2 Release。
環境搭建
完成本篇Codelab我們首先要完成開發環境的搭建,本示例以RK3568開發板為例,參照以下步驟進行:
- [獲取OpenHarmony系統版本]:標準系統解決方案(二進制)。以3.2 Release版本為例:
- 搭建燒錄環境。
- [完成DevEco Device Tool的安裝]
- [完成RK3568開發板的燒錄]
- 搭建開發環境。
- 開始前請參考[工具準備],完成DevEco Studio的安裝和開發環境配置。
- 開發環境配置完成后,請參考[使用工程向導]創建工程(模板選擇“Empty Ability”)。
- 工程創建完成后,選擇使用[真機進行調測]。
- 鴻蒙開發指導文檔:[
qr23.cn/FBD4cY
]
代碼結構解讀
本篇Codelab只對核心代碼進行講解,完整代碼可以直接從gitee獲取。
├──entry/src/main/ets // 代碼區
│ ├──common // 公共文件目錄
│ │ └──constants
│ │ └──Constants.ets // 常量
│ ├──entryability
│ │ └──EntryAbility.ts // 應用的入口
│ ├──model
│ │ └──DataModel.ets // 模擬數據
│ ├──pages
│ │ └──RankPage.ets // 入口頁面
│ ├──view // 自定義組件目錄
│ │ ├──ListHeaderComponent.ets
│ │ ├──ListItemComponent.ets
│ │ └──TitleComponent.ets
│ └──viewmodel
│ ├──RankData.ets // 實體類
│ └──RankViewModel.ets // 視圖業務邏輯類
└──entry/src/main/resources // 資源文件目錄
`HarmonyOS與OpenHarmony鴻蒙文檔籽料:mau123789是v直接拿`
使用@Link封裝標題組件
在TitleComponent文件中,首先使用struct對象創建自定義組件,然后使用@Link修飾器管理TitleComponent組件內的狀態變量isRefreshData,狀態變量isRefreshData值發生改變后,通過@Link裝飾器通知頁面刷新List中的數據。代碼如下:
// TitleComponent.ets
...
@Component
export struct TitleComponent {
@Link isRefreshData: boolean; // 判斷是否刷新數據
@State title: Resource = $r('app.string.title_default');
build() {
Row() {
...
Row() {
Image($r('app.media.loading'))
.height(TitleBarStyle.IMAGE_LOADING_SIZE)
.width(TitleBarStyle.IMAGE_LOADING_SIZE)
.onClick(() = > {
this.isRefreshData = !this.isRefreshData;
})
}
.width(TitleBarStyle.WEIGHT)
.height(WEIGHT)
.justifyContent(FlexAlign.End)
}
...
}
}
效果如圖所示:
封裝列表頭部樣式組件
在ListHeaderComponent文件中,我們使用常規成員變量來設置自定義組件ListHeaderComponent的widthValue和paddingValue,代碼如下:
// ListHeaderComponent.ets
...
@Component
export struct ListHeaderComponent {
paddingValue: Padding | Length = 0;
widthValue: Length = 0;
build() {
Row() {
Text($r('app.string.page_number'))
.fontSize(FontSize.SMALL)
.width(ListHeaderStyle.LAYOUT_WEIGHT_LEFT)
.fontWeight(ListHeaderStyle.FONT_WEIGHT)
.fontColor($r('app.color.font_description'))
Text($r('app.string.page_type'))
.fontSize(FontSize.SMALL)
.width(ListHeaderStyle.LAYOUT_WEIGHT_CENTER)
.fontWeight(ListHeaderStyle.FONT_WEIGHT)
.fontColor($r('app.color.font_description'))
Text($r('app.string.page_vote'))
.fontSize(FontSize.SMALL)
.width(ListHeaderStyle.LAYOUT_WEIGHT_RIGHT)
.fontWeight(ListHeaderStyle.FONT_WEIGHT)
.fontColor($r('app.color.font_description'))
}
.width(this.widthValue)
.padding(this.paddingValue)
}
}
效果如圖所示:
創建ListItemComponent
為了體現@Prop單向綁定功能,我們在ListItemComponent組件中添加了一個@Prop修飾的字段isSwitchDataSource,當通過點擊改變ListItemComponent組件中isSwitchDataSource狀態時,ListItemComponent作為List的子組件,并不會通知其父組件List刷新狀態。
在代碼中,我們使用@State管理ListItemComponent中的 isChange 狀態,當用戶點擊ListItemComponent時,ListItemComponent組件中的文本顏色發生變化。我們使用條件渲染控制語句,創建的圓型文本組件。
// ListItemComponent.ets
...
@Component
export struct ListItemComponent {
index?: number;
private name?: Resource;
@Prop vote: string = '';
@Prop isSwitchDataSource: boolean = false;
// 判斷是否改變ListItemComponent字體顏色
@State isChange: boolean = false;
build() {
Row() {
Column() {
if (this.isRenderCircleText()) {
if (this.index !== undefined) {
this.CircleText(this.index);
}
} else {
Text(this.index?.toString())
.lineHeight(ItemStyle.TEXT_LAYOUT_SIZE)
.textAlign(TextAlign.Center)
.width(ItemStyle.TEXT_LAYOUT_SIZE)
.fontWeight(FontWeight.BOLD)
.fontSize(FontSize.SMALL)
}
}
.width(ItemStyle.LAYOUT_WEIGHT_LEFT)
.alignItems(HorizontalAlign.Start)
Text(this.name)
.width(ItemStyle.LAYOUT_WEIGHT_CENTER)
.fontWeight(FontWeight.BOLDER)
.fontSize(FontSize.MIDDLE)
.fontColor(this.isChange ? ItemStyle.COLOR_BLUE : ItemStyle.COLOR_BLACK)
Text(this.vote)
.width(ItemStyle.LAYOUT_WEIGHT_RIGHT)
.fontWeight(FontWeight.BOLD)
.fontSize(FontSize.SMALL)
.fontColor(this.isChange ? ItemStyle.COLOR_BLUE : ItemStyle.COLOR_BLACK)
}
.height(ItemStyle.BAR_HEIGHT)
.width(WEIGHT)
.onClick(() = > {
this.isSwitchDataSource = !this.isSwitchDataSource;
this.isChange = !this.isChange;
})
}
...
}
效果如圖所示:
創建RankList
為了簡化代碼,提高代碼的可讀性,我們使用@Builder描述排行列表布局內容,使用循環渲染組件ForEach創建ListItem。代碼如下:
// RankPage.ets
...
build() {
Column() {
// 頂部標題組件
TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE })
// 列表頭部樣式
ListHeaderComponent({
paddingValue: {
left: Style.RANK_PADDING,
right: Style.RANK_PADDING
},
widthValue: Style.CONTENT_WIDTH
})
.margin({
top: Style.HEADER_MARGIN_TOP,
bottom: Style.HEADER_MARGIN_BOTTOM
})
// 列表區域
this.RankList(Style.CONTENT_WIDTH)
}
.backgroundColor($r('app.color.background'))
.height(WEIGHT)
.width(WEIGHT)
}
@Builder RankList(widthValue: Length) {
Column() {
List() {
ForEach(this.isSwitchDataSource ? this.dataSource1 : this.dataSource2,
(item: RankData, index?: number) = > {
ListItem() {
ListItemComponent({ index: (Number(index) + 1), name: item.name, vote: item.vote,
isSwitchDataSource: this.isSwitchDataSource
})
}
}, (item: RankData) = > JSON.stringify(item))
}
.width(WEIGHT)
.height(Style.LIST_HEIGHT)
.divider({ strokeWidth: Style.STROKE_WIDTH })
}
.padding({
left: Style.RANK_PADDING,
right: Style.RANK_PADDING
})
.borderRadius(Style.BORDER_RADIUS)
.width(widthValue)
.alignItems(HorizontalAlign.Center)
.backgroundColor(Color.White)
}
...
效果如圖所示:
使用自定義組件生命周期函數
我們通過點擊系統導航返回按鈕來演示onBackPress回調方法的使用,在指定的時間段內,如果滿足退出條件,onBackPress將返回false,系統默認關閉當前頁面。否則,提示用戶需要再點擊一次才能退出,同時onBackPress返回true,表示用戶自己處理導航返回事件。代碼如下:
// RankPage.ets
...
@Entry
@Component
struct RankPage {
...
onBackPress() {
if (this.isShowToast()) {
prompt.showToast({
message: $r('app.string.prompt_text'),
duration: TIME
});
this.clickBackTimeRecord = new Date().getTime();
return true;
}
return false;
}
...
}
審核編輯 黃宇
-
變量
+關注
關注
0文章
613瀏覽量
28360 -
鴻蒙
+關注
關注
57文章
2339瀏覽量
42805 -
HarmonyOS
+關注
關注
79文章
1973瀏覽量
30143 -
OpenHarmony
+關注
關注
25文章
3713瀏覽量
16254 -
RK3568
+關注
關注
4文章
514瀏覽量
5034
發布評論請先 登錄
相關推薦
評論