赞
踩
列表是一种复杂的容器,当列表项达到一定数量,内容超过屏幕大小时,可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集,例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求(如通讯录、音乐列表、购物清单等)。
使用列表可以轻松高效地显示结构化、可滚动的信息。通过在List组件中按垂直或者水平方向线性排列子组件ListItemGroup或ListItem,为列表中的行或列提供单个视图,或使用ForEach迭代一组行或列,或混合任意数量的单个视图和ForEach结构,构建一个列表。List组件支持使用条件渲染、循环渲染、懒加载等渲染控制方式生成子组件。
以下代码均经过我 demo 的实战验证,确保代码和效果对应
列表作为一种容器,会自动按其滚动方向排列子组件,向列表中添加组件或从列表中移除组件会重新排列子组件。
如下图所示,在垂直列表中,List按垂直方向自动排列ListItemGroup或ListItem。
ListItemGroup用于列表数据的分组展示,其子组件也是ListItem。ListItem表示单个列表项,可以包含单个子组件。
List除了提供垂直和水平布局能力、超出屏幕时可以滚动的自适应延伸能力之外,还提供了自适应交叉轴方向上排列个数的布局能力。
利用垂直布局能力可以构建单列或者多列垂直滚动列表,如下图所示。
@Entry @Component struct ListVerticalPage { @State listItems:Array<String> = [] aboutToAppear() { for (var i =0;i< 50;i++) { this.listItems.push("") } } build() { Navigation() { List({space: 5}) { ForEach(this.listItems, ()=> { ListItem() { Stack() .width('100%') .height(100) .backgroundColor('#9dc3e6') } .padding({left:15, right:15}) }) } } .title('垂直滚动列表') .titleMode(NavigationTitleMode.Mini) } }
@Entry @Component struct ListMultiVerticalPage { @State listItems:Array<String> = [] aboutToAppear() { for (var i =0;i< 50;i++) { this.listItems.push("") } } build() { Navigation() { List({space: 5}) { ForEach(this.listItems, ()=> { ListItem() { Stack() .width('100%') .height(100) .backgroundColor('#9dc3e6') }.padding({left:2,right:2}) }) } .lanes(2) } .title('垂直滚动多列') .titleMode(NavigationTitleMode.Mini) } }
@Entry @Component struct ListHorizontalPage { @State listItems:Array<String> = [] aboutToAppear() { for (var i =0;i< 50;i++) { this.listItems.push(`${i+1}`) } } build() { Navigation() { List({space: 5}) { ForEach(this.listItems, (item:string)=> { ListItem() { Text(item) .textAlign(TextAlign.Center) .width(50) .height(300) .backgroundColor('#9dc3e6') } }) }.listDirection(Axis.Horizontal) } .title('水平滚动列表') .titleMode(NavigationTitleMode.Mini) } }
@Entry @Component struct ListMultiHorizontalPage { @State listItems:Array<String> = [] aboutToAppear() { for (var i =0;i< 50;i++) { this.listItems.push(`${i+1}`) } } build() { Navigation() { List({space: 5}) { ForEach(this.listItems, (item:string)=> { ListItem() { Text(item) .textAlign(TextAlign.Center) .width(50) .height(300) .backgroundColor('#9dc3e6') } }) } .lanes(2) .listDirection(Axis.Horizontal) } .title('水平滚动多列') .titleMode(NavigationTitleMode.Mini) } }
在初始化列表时,如需在列表项之间添加间距,可以使用 space 参数。例如,在每个列表项之间沿主轴方向添加 55vp 的间距:
对应局部代码
List({space: 55}) {
ForEach(this.listItems, ()=> {
ListItem() {
Stack()
.width('100%')
.height(100)
.backgroundColor('#9dc3e6')
}
})
}
效果图
对应代码
List() { ForEach(this.listItems, ()=> { ListItem() { Stack() .width('100%') .height(100) .backgroundColor('#9dc3e6') } }) } .divider({ strokeWidth: 1, startMargin: 60, endMargin: 10, color: '#ff0000' })
效果图
对应代码
List() {
ForEach(this.listItems, ()=> {
ListItem() {
Stack()
.width('100%')
.height(100)
.backgroundColor('#9dc3e6')
}
})
}
.scrollBar(BarState.Auto)
.divider({
strokeWidth: 1,
color: '#ff0000'
})
在列表中支持数据的分组展示,可以使列表显示结构清晰,查找方便,从而提高使用效率。分组列表在实际应用中十分常见,如下图所示联系人列表。
对应代码
import router from '@ohos.router' import { CodeView } from '../../../widget/CodeView' interface ContactGroup { title:string contacts:Array<String> } @Entry @Component struct GroupListPage { contactsGroups: ContactGroup[] = [ { title: 'A', contacts: [ "安以轩", "安悦溪", ], }, { title: 'B', contacts: [ "白敬亭", "白宇", ], }, ... } ] @Builder itemHead(text: string) { // 列表分组的头部组件,对应联系人分组A、B等位置的组件 Text(text) .fontSize(20) .width('100%') .padding(10) .backgroundColor('#ffffff') .fontWeight(FontWeight.Bold) } @Builder itemContent(text: string) { // 列表分组的头部组件,对应联系人分组A、B等位置的组件 Text(text) .padding({ left: 10, bottom: 10, top: 10 }) } build() { Navigation() { List() { ForEach(this.contactsGroups, (item:ContactGroup)=>{ ListItemGroup({ header: this.itemHead(item.title) }) { ForEach(item.contacts, (name:string)=> { ListItem() { this.itemContent(name) } }) } }) } } .title('支持分组列表') .titleMode(NavigationTitleMode.Mini) } }
运行效果
对应代码
List() {
...
}
.sticky(StickyStyle.Header) // 设置吸顶,实现粘性标题效果
对应代码
@Entry @Component struct ListScrollToPage { @State listItems:Array<String> = [] private listScroller: Scroller = new Scroller(); aboutToAppear() { for (var i =0;i< 50;i++) { this.listItems.push(`新闻${i+1}`) } } build() { Navigation() { Stack({ alignContent: Alignment.BottomEnd }) { List({ space: 5, scroller: this.listScroller }) { ForEach(this.listItems, (text: string) => { ListItem() { Text(text) .textAlign(TextAlign.Center) .width('100%') .height(250) .backgroundColor('#9dc3e6') } }) } Image('image/scroll_to_top.svg') .width(50) .height(50) .margin({right: 10,bottom: 10}) .onClick(()=> { this.listScroller.scrollToIndex(0) }) } } .title('控制滚动位置') .titleMode(NavigationTitleMode.Mini) } }
对应代码
Stack() {
List() {
...
}
.onScrollIndex((start, end)=> {
this.firstIndex = start
})
Text(`当前第一个index:${this.firstIndex}`)
...
}
对应代码
@Entry @Component struct SwipeListPage { @State listItems:Array<String> = [] aboutToAppear() { for (var i =0;i< 50;i++) { this.listItems.push(`选项${i+1}`) } } @Builder itemEnd(index: number) { // 侧滑后尾端出现的组件 Image("image/delete.svg") .width(20) .height(20) .onClick(() => { this.listItems.splice(index, 1); }) } build() { Navigation() { List({space: 5}) { ForEach(this.listItems, (item, index)=> { ListItem() { Text(item) .textAlign(TextAlign.Center) .width('100%') .height(50) .backgroundColor('#9dc3e6') } .swipeAction({ end: this.itemEnd.bind(this,index) }) }) } } .title('左滑删除列表') .titleMode(NavigationTitleMode.Mini) } }
添加标记是一种无干扰性且直观的方法,用于显示通知或将注意力集中到应用内的某个区域。例如,当消息列表接收到新消息时,通常对应的联系人头像的右上方会出现标记,提示有若干条未读消息,如下图所示。
@Entry @Component struct BadgeListPage { @State listItems:Array<String> = [] aboutToAppear() { for (var i =0;i< 50;i++) { this.listItems.push(`Item${i+1}`) } } build() { Navigation() { List({space: 5}) { ForEach(this.listItems, (item:string)=> { ListItem() { Row() { // 展示未读数 Badge({ count: 1, position: BadgePosition.RightTop, style: { badgeSize: 16, badgeColor: '#FA2A2D' } }) { // 未读数的头像 Button() .width(80) .height(80) .border({radius:90}) }.margin({left:15}) // 右侧文字 Text(item) .fontColor(Color.White) .width('100%') .height(100) .padding({left:20}) } } }) }.backgroundColor(Color.Gray) } .title('列表项添加标记') .titleMode(NavigationTitleMode.Mini) } }
循环渲染适用于短列表,当构建具有大量列表项的长列表时,如果直接采用循环渲染方式,会一次性加载所有的列表元素,会导致页面启动时间过长,影响用户体验。因此,推荐使用数据懒加载(LazyForEach)方式实现按需迭代加载数据,从而提升列表性能。
当使用懒加载方式渲染列表时,为了更好的列表滚动体验,减少列表滑动时出现白块,List组件提供了cachedCount参数用于设置列表项缓存数,只在懒加载LazyForEach中生效。
@Entry @Component struct LazyForEachPage { dataSource:MyDataSource = new MyDataSource(); aboutToAppear() { for (var i =0;i< 50;i++) { this.dataSource.pushData(`Item${i+1}`) } } build() { Navigation() { List({space: 5}) { LazyForEach(this.dataSource, (item:string)=> { ListItem() { Text(item) .width('100%') .height(100) .backgroundColor('#9dc3e6') } }) } } .title('LazyForEach 列表') .titleMode(NavigationTitleMode.Mini) } } // Basic implementation of IDataSource to handle data listener class BasicDataSource implements IDataSource { private listeners: DataChangeListener[] = []; getData(index: number) { return "" } totalCount(): number { return 0 } // 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听 registerDataChangeListener(listener: DataChangeListener): void { if (this.listeners.indexOf(listener) < 0) { console.info('add listener'); this.listeners.push(listener); } } // 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听 unregisterDataChangeListener(listener: DataChangeListener): void { const pos = this.listeners.indexOf(listener); if (pos >= 0) { console.info('remove listener'); this.listeners.splice(pos, 1); } } // 通知LazyForEach组件需要重载所有子组件 notifyDataReload(): void { this.listeners.forEach(listener => { listener.onDataReloaded(); }) } // 通知LazyForEach组件需要在index对应索引处添加子组件 notifyDataAdd(index: number): void { this.listeners.forEach(listener => { listener.onDataAdd(index); }) } // 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件 notifyDataChange(index: number): void { this.listeners.forEach(listener => { listener.onDataChange(index); }) } // 通知LazyForEach组件需要在index对应索引处删除该子组件 notifyDataDelete(index: number): void { this.listeners.forEach(listener => { listener.onDataDelete(index); }) } } class MyDataSource extends BasicDataSource { private dataArray: string[] = []; totalCount(): number { return this.dataArray.length; } getData(index: number) { return this.dataArray[index]; } public addData(index: number, data: string): void { this.dataArray.splice(index, 0, data); this.notifyDataAdd(index); } public pushData(data: string): void { this.dataArray.push(data); this.notifyDataAdd(this.dataArray.length - 1); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。