HarmonyOS 通用列表流程使用指南
參考文檔
- 華為開發者聯盟 - 常見列表流開發實踐
概述
列表流是採用以"行"為單位進行內容排列的佈局形式,每"行"列表項通過文本、圖片等不同形式的組合,高效地顯示結構化的信息,當列表項內容超過屏幕大小時,可以提供滾動功能。
列表流具有以下特點:
- 排版整齊
- 重點突出
- 對比方便
- 瀏覽速度快
常見使用場景包括:應用首頁、通訊錄、音樂列表、購物清單等。
在 HarmonyOS 中,列表流主要使用 List 組件,按垂直方向線性排列子組件 ListItemGroup 或 ListItem,混合渲染任意數量的圖文視圖,從而構建列表內容。
基礎組件
List 組件
List 是最基礎的列表容器組件,用於創建可滾動的列表。
import { Column, List, ListItem, Text } from '@ohos/components';
@Entry
@Component
struct BasicListExample {
private listData: string[] = ['列表項1', '列表項2', '列表項3', '列表項4', '列表項5'];
build() {
Column() {
List({
scroller: null,
space: 20
})
.width('100%')
.height('100%')
.onScrollIndex((start: number, end: number) => {
// 滾動事件處理
})
.onReachStart(() => {
// 滾動到頂部
})
.onReachEnd(() => {
// 滾動到底部,可用於加載更多
})
.onScrollStop(() => {
// 滾動停止
})
{
ForEach(this.listData, (item) => {
ListItem() {
Text(item)
.width('100%')
.height(60)
.textAlign(TextAlign.Center)
.fontSize(16)
}
.backgroundColor('#f0f0f0')
.margin({ left: 16, right: 16 })
}, item => item)
}
}
.padding(16)
}
}
常見列表流場景實現
1. 多類型列表項場景
場景描述
List 組件作為整個首頁長列表的容器,通過 ListItem 對不同模塊進行視圖界面定製,常用於門户首頁、商城首頁等多類型視圖展示的列表信息流場景。
實現原理
根據列表內部各部分視圖對應數據類型的區別,渲染不同的 ListItem 子組件。
import { Column, List, ListItem, Text, Image, Grid, GridItem } from '@ohos/components';
@Entry
@Component
struct MultiTypeListExample {
// 模擬數據
private bannerData = {
images: ['banner1.png', 'banner2.png'],
type: 'banner'
};
private recommendData = [
{ id: 1, title: '推薦內容1', image: 'rec1.png' },
{ id: 2, title: '推薦內容2', image: 'rec2.png' },
{ id: 3, title: '推薦內容3', image: 'rec3.png' },
{ id: 4, title: '推薦內容4', image: 'rec4.png' },
];
private articleData = [
{ id: 1, title: '文章標題1', desc: '文章描述1', type: 'article' },
{ id: 2, title: '文章標題2', desc: '文章描述2', type: 'article' },
];
build() {
Column() {
List() {
// Banner類型列表項
ListItem() {
Column() {
Text('Banner區域')
.fontSize(18)
.fontWeight(FontWeight.Bold)
// 這裏可以放置輪播圖組件
Image(this.bannerData.images[0])
.width('100%')
.height(200)
.borderRadius(12)
}
.padding(16)
}
// 推薦內容類型列表項
ListItem() {
Column() {
Text('推薦內容')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 16 })
Grid() {
ForEach(this.recommendData, (item) => {
GridItem() {
Column() {
Image(item.image)
.width('100%')
.height(120)
.aspectRatio(1)
Text(item.title)
.fontSize(14)
.margin({ top: 8 })
}
}
}, item => item.id)
}
.columnsTemplate('1fr 1fr')
.columnsGap(16)
.rowsGap(16)
}
.padding(16)
}
// 文章列表類型列表項
ListItem() {
Column() {
Text('最新文章')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 16 })
ForEach(this.articleData, (item) => {
Column() {
Text(item.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(item.desc)
.fontSize(14)
.fontColor('#666666')
.margin({ top: 8 })
}
.padding(16)
.backgroundColor('#f5f5f5')
.borderRadius(8)
.margin({ bottom: 12 })
}, item => item.id)
}
.padding(16)
}
}
}
}
}
2. Tabs 吸頂場景
場景描述
當頁面包含 Tabs 組件時,實現 Tabs 在滾動到頂部後保持吸頂狀態,常用於分類瀏覽、數據篩選等場景。
實現原理
使用 List 組件的 sticky 屬性實現元素吸頂效果。
import { Column, List, ListItem, Tabs, TabContent, Text } from '@ohos/components';
@Entry
@Component
struct StickyTabsExample {
private tabList: string[] = ['推薦', '關注', '熱門', '最新'];
build() {
Column() {
// 頁面頂部內容
Column() {
Text('頁面標題')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.padding(16)
}
// 可吸頂的Tabs組件
Tabs() {
ForEach(this.tabList, (tab) => {
TabContent() {
List() {
ListItem() {
Text(`${tab}內容列表`)
.fontSize(16)
.padding(20)
}
// 生成更多列表項
ForEach(Array.from({ length: 20 }), (_, index) => {
ListItem() {
Text(`${tab}內容 ${index + 1}`)
.fontSize(16)
.padding(20)
.backgroundColor('#f5f5f5')
.margin({ left: 16, right: 16, top: 12 })
.borderRadius(8)
}
})
}
}
.tabBar(tab)
})
}
.width('100%')
.height('80%')
.barMode(BarMode.Scrollable)
.scrollable(true)
}
}
}
3. 分組吸頂場景
場景描述
列表內容按分組展示,每個分組的標題在滾動到頂部時保持吸頂狀態,常用於聯繫人列表、城市選擇等場景。
實現原理
使用 ListItemGroup 組件創建分組,並設置 sticky 屬性實現分組標題吸頂。
import { Column, List, ListItemGroup, ListItem, Text } from '@ohos/components';
@Entry
@Component
struct GroupStickyExample {
// 模擬分組數據
private groupData = [
{
title: 'A',
items: ['Alice', 'Amy', 'Anna']
},
{
title: 'B',
items: ['Bob', 'Bill']
},
{
title: 'C',
items: ['Charlie', 'Cathy', 'Carol']
}
];
build() {
Column() {
Text('聯繫人列表')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.padding(16)
List() {
ForEach(this.groupData, (group) => {
ListItemGroup({
header: () => {
// 分組標題
return (
Text(group.title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.backgroundColor('#e0e0e0')
.padding(12)
.width('100%')
)
},
footer: () => {
// 分組底部
return null;
},
sticky: ListItemStickyStyle.Header
})
{
// 分組內的列表項
ForEach(group.items, (item) => {
ListItem() {
Text(item)
.fontSize(16)
.padding(16)
.width('100%')
}
.borderBottom({ width: 1, color: '#f0f0f0' })
})
}
})
}
.width('100%')
.height('80%')
}
}
}
4. 二級聯動場景
場景描述
左側為分類列表,右側為對應分類下的內容列表,滾動右側內容時左側分類同步高亮顯示,點擊左側分類時右側內容滾動到對應位置,常用於商品分類、點餐應用等場景。
實現原理
通過監聽左右兩側列表的滾動和點擊事件,實現聯動效果。
import { Column, Row, List, ListItem, Text, Scroll, ScrollController } from '@ohos/components';
@Entry
@Component
struct TwoLevelLinkageExample {
private categories = ['分類1', '分類2', '分類3', '分類4', '分類5'];
private selectedIndex: number = 0;
private scrollController: ScrollController = new ScrollController();
// 模擬分類內容數據
private categoryData = {
'分類1': ['商品1-1', '商品1-2', '商品1-3', '商品1-4'],
'分類2': ['商品2-1', '商品2-2'],
'分類3': ['商品3-1', '商品3-2', '商品3-3'],
'分類4': ['商品4-1', '商品4-2', '商品4-3', '商品4-4', '商品4-5'],
'分類5': ['商品5-1', '商品5-2']
};
// 點擊分類處理函數
onCategoryClick(index: number) {
this.selectedIndex = index;
// 滾動到對應位置
this.scrollController.scrollTo({ xOffset: 0, yOffset: 0 });
}
build() {
Column() {
Row() {
// 左側分類列表
List() {
ForEach(this.categories, (category, index) => {
ListItem() {
Text(category)
.fontSize(16)
.padding(16)
.width('100%')
.backgroundColor(this.selectedIndex === index ? '#e6f7ff' : '#ffffff')
.fontColor(this.selectedIndex === index ? '#1890ff' : '#000000')
.onClick(() => this.onCategoryClick(index))
}
.borderBottom({ width: 1, color: '#f0f0f0' })
})
}
.width('30%')
.height('80%')
// 右側內容列表
Scroll(this.scrollController) {
Column() {
ForEach(this.categoryData[this.categories[this.selectedIndex]], (item) => {
Text(item)
.fontSize(16)
.padding(16)
.width('100%')
.backgroundColor('#f5f5f5')
.margin({ bottom: 12 })
.borderRadius(8)
})
}
.padding(16)
}
.width('70%')
.height('80%')
}
}
}
}
性能優化
1. 虛擬化渲染
HarmonyOS 的 List 組件默認開啓虛擬化渲染,只會渲染可視區域內的列表項,以及少量緩衝區的列表項,可以有效減少內存佔用和提高渲染性能。
2. 懶加載
對於列表中的圖片等資源,可以實現懶加載,只在圖片即將進入可視區域時再加載。
import { Image } from '@ohos/components';
// 自定義懶加載圖片組件
@Component
struct LazyLoadImage {
@Prop src: string;
private isLoaded: boolean = false;
// 當組件可見時加載圖片
onVisibleChanged(visible: boolean) {
if (visible && !this.isLoaded) {
this.isLoaded = true;
}
}
build() {
Image(this.isLoaded ? this.src : '')
.onVisible(this.onVisibleChanged)
.width('100%')
.height(200)
}
}
3. 避免不必要的重渲染
使用memo、@Watch等機制,避免組件不必要的重渲染。
// 使用memo優化子組件
const MemoizedListItem = memo((props: { data: any }) => {
return (
ListItem() {
Text(props.data.title)
.fontSize(16)
.padding(16)
}
);
});
注意事項與最佳實踐
1. 列表項高度設置
為了提高渲染性能,建議為列表項設置固定高度或最大高度,避免動態高度導致的佈局重計算。
2. 大數據量處理
當列表數據量較大時:
- 實現分頁加載
- 使用虛擬列表
- 避免在滾動過程中執行復雜計算
3. 事件處理優化
- 使用事件委託減少事件監聽器數量
- 避免在
onScroll等頻繁觸發的事件中執行耗時操作
List()
.onScroll(() => {
// 避免在這裏執行復雜計算
})
// 可以使用節流處理
.onScrollThrottle(300, () => {
// 每300ms最多執行一次
});
4. 列表緩存
對於頻繁訪問的列表數據,可以實現緩存機制,減少重複請求。
常見問題解答
Q: List 組件和 Scroll 組件有什麼區別?
A: List 組件專為列表數據展示優化,支持虛擬化渲染、分組、粘性頭部等功能,性能更好;Scroll 組件是通用的滾動容器,功能更靈活但性能相對較差。
Q: 如何實現列表的下拉刷新和上拉加載更多?
A: 可以使用 Refresh 組件實現下拉刷新,結合 List 的 onReachEnd 事件實現上拉加載更多。
Refresh({
refreshing: this.isRefreshing,
onRefresh: () => {
// 下拉刷新邏輯
this.loadData();
},
});
{
List().onReachEnd(() => {
// 上拉加載更多邏輯
this.loadMoreData();
});
}
Q: 如何優化長列表的性能?
A:
- 使用固定高度的列表項
- 開啓虛擬化渲染
- 實現懶加載
- 避免在滾動過程中執行復雜操作
- 使用 memo 優化組件渲染
總結
HarmonyOS 的列表流開發主要使用 List 組件,可以實現多種複雜的列表場景。通過本文介紹的多類型列表項、Tabs 吸頂、分組吸頂和二級聯動等場景的實現方法,開發者可以快速構建出功能豐富、性能優良的列表頁面。在實際開發中,還需要注意性能優化和用户體驗,確保列表滾動流暢,響應迅速。