介紹
在很多應用中,向上滑動"我的"頁面,頁面頂部會有如下變化效果:一部分資訊逐漸隱藏,另一部分資訊逐漸顯示,同時一些元件會進行縮放或者位置移動。向下滑動時則相反。
效果圖預覽
使用說明
- 向上滑動頁面,出現如下變化:使用者名稱/選擇身份/設定圖示/客服圖示逐漸隱藏,使用者頭像尺寸逐漸縮小並向右上平移,頂部"返回"文字後方使用者名稱逐漸顯示。
- 滑動到頂部後,向下滑動頁面,出現如下變化:使用者頭像尺寸逐漸變大並向左下平移,頂部"返回"文字後方的使用者名稱逐漸隱藏,原來的使用者名稱/選擇身份/設定圖示/客服圖示逐漸顯示。
實現思路
本例涉及的關鍵特性和實現方案如下:
- 將螢幕從上向下分為三部分,第一部分Row元件包含"返回"和初始狀態下隱藏的使用者名稱,第二部分Row包含使用者頭像/使用者名稱/選擇身份/設定/客服,下方其餘部分位第三部分。本例場景的變化體現在第一和第二部分。原始碼參考SlideToHideAndDisplace
Column() {
Row() {...}
.padding($r('app.integer.padding_small'))
.width($r('app.string.size_full'))
.alignItems(VerticalAlign.Center)
Row() {...}
.height($r('app.integer.height_one_hundred'))
.width($r('app.string.size_full'))
Scroll() {...}
}
- 在第一和第二部分中,使用@State裝飾器裝飾相關的元件屬性,使之與自定義元件的渲染繫結起來,狀態變數改變時,UI會發生對應的渲染改變。使用者頭像的縮放透過改變其width和height屬性值的大小來重新整理,使用者頭像的位移透過改變其margin屬性中的top和left的大小來重新整理。其他一些元件的顯隱變化透過改變其opacity屬性值的大小來重新整理。原始碼參考SlideToHideAndDisplace
@State userRowOpacity: number = 1;
@State userImageHeight: number = 50;
...
build() {
Column() {
Row() {
...
Text($r('app.string.phone_number'))
.opacity(this.userNameOpacity) // userNameOpacity控制頂部使用者名稱的透明度
Blank()
Text("設定")
.opacity(this.userNameOpacity) // 設定的文字透明度與頂部使用者名稱相同
Text("客服")
.opacity(this.userNameOpacity) // 客服的文字透明度與頂部使用者名稱相同
}
Row() {
Image($r('app.media.batman'))
.width(this.userImageHeight)
.height(this.userImageHeight) // userImageHeight控制頭像尺寸
// userImageMarginTop和userImageMarginLeft控制頭像在父容器內的位置
.margin({ top: this.userImageMarginTop, left: this.userImageMarginLeft })
Column() {...}
.alignItems(HorizontalAlign.Start)
.opacity(this.userRowOpacity) // 控制Row元件的透明度
}
...
}
}
- 第三部分頁面滾動透過Scroll元件實現,其中第二欄和第三欄相似,使用@Builder裝飾器封裝了兩個自定義構建函式IconAndDescription和CustomRow,增加程式碼複用。原始碼參考SlideToHideAndDisplace
// 自定義構建函式,將重複使用的UI元素抽象成一個方法。此處樣式為:上方圖示下方文字
@Builder
IconAndDescription(icon: Resource, description: string | Resource, iconSize?: Size, radius?: number) {
Column() {
Image(icon)
.size(iconSize === undefined ? { height: $r('app.integer.icon_default_height'),
width: $r('app.integer.icon_default_height') } : iconSize)
.borderRadius(radius)
Text(description)
.margin({ top: $r('app.integer.margin_between_icon_and_description') })
}
}
// 自定義構建函式。此處樣式為:在Row元件中橫向排列IconAndDescription
@Builder
CustomRow(iconsAndDescriptions: IconAndDescription[]) {
Row() {
ForEach(iconsAndDescriptions, (item: IconAndDescription) => {
this.IconAndDescription(item.icon, item.description)
})
}
.width($r('app.string.size_full'))
.justifyContent(FlexAlign.SpaceAround)
.padding($r('app.integer.padding_small'))
.margin({ top: $r('app.integer.margin_small') })
.backgroundColor($r('app.color.color_transparent_aa'))
.borderRadius($r('app.integer.border_radius'))
}
高效能知識點
本例中Scroll元件繫結onScroll滾動事件回撥,onScroll屬於頻繁回撥,在回撥中需要儘量減少耗時和冗餘操作,例如減少不必要的日誌列印。
工程結構&模組型別
slidetohideanddisplace // har包
|---model
| |---Util.ets // 提供測試資料類
|---SlideToHideAndDisplace.ets // 滑動變化效果實現頁面
模組依賴
不涉及。
參考資料
@State裝飾器
@Builder裝飾器
透明度設定
Scroll
學習鴻蒙開發勢在必行。鴻蒙開發可參考學習文件:https://qr21.cn/FV7h05