HarmonyOS应用开发之ArkUI 滚动列表List全面解析,建议收藏

28 阅读3分钟

列表(List)

List列表组件是最常用的容器器组件之一,当列表项达到一定数量,内容超过列表尺寸大小时,可以自动提供滚动功能。使用列表可以轻松高效地显示结构化、可滚动的信息。 在这里插入图片描述

创建列表

List列表中的每一个列表项用ListItem来表示,List必须嵌套ListItem一起使用。

如下图所示,这是一个简单的列表,每一个列表项显示一个文本。

在这里插入图片描述

代码如下,其中.divider()属性用于给列表项设置分割线。

@Entry
@Component
struct Index {
  build() {
    Column() {
      List({ space: 10 }) {
        ListItem(){
          Text('0').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('1').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('2').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('3').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('4').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('5').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('6').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('7').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('8').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('9').width("100%").height(100).textAlign(TextAlign.Center)
        }
        ListItem(){
          Text('10').width("100%").height(100).textAlign(TextAlign.Center)
        }
      }.divider({
        strokeWidth: 1,
        color: "#dedede",
        startMargin: 10,
        endMargin: 10
      })
    }.width("100%")
    .height("100%")
  }
}

列表样式

  • 通过{ space: 10 }参数用来设置列表项之间的间距;
List({ space: 10 }) {
  // ...
}
  • 通过.divider()属性用来设置列表项之间的分割线;
List() {
  // ...
}
.divider({
  strokeWidth: 0.5,	//分割线的粗细
  color:Color.Black	//分割线的颜色
})
  • 通过.scrollBar()属性用来设置滚动条的显示模式;
List() {
  // ...
}
.scrollBar(BarState.Auto) //默认不显示,滚动时显示,2秒后消失
  • 通过.listDirection() 属性设置列表滚动方向
List() {
  // ...
}
.listDirection(Axis.Horizontal)

循环渲染

一般情况下List列表项的UI结构都是相同的,可以采用ForEach循环渲染所有列表项。

ForEach有如下特点

  • List组件创建时,所有ListItem将会被创建。

  • 显示区域内的ListItem在首帧进行布局,预加载范围内的ListItem在空闲时完成布局。预加载范围之外的ListItem仅创建ListItem自身,ListItem其内部的子组件不会被创建。

  • List组件滑动时,进入预加载及显示区域的ListItem将会创建其内部的子组件并完成布局,而滑出预加载及显示区域的ListItem将不会被销毁。

在这里插入图片描述

代码如下

@Entry
@Component
struct Index {
  @State array: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

  build() {
    Column() {
      List({ space: 10 }) {
        ForEach(this.array,(item:number)=>{
          ListItem(){
            Text(`${item}`).width("100%").height(100).textAlign(TextAlign.Center)
          }
        })
      }.divider({
        strokeWidth: 1,
        color: "#dedede",
        startMargin: 10,
        endMargin: 10
      })
    }.width("100%")
    .height("100%")
  }
}

复杂列表

当列表项的UI结构较为复杂时,建议采用@Builder装饰器对UI组件进行封装以实现复用,同时将列表数据封装为独立的对象模型,从而实现UI展示与数据逻辑的彻底解耦。

在这里插入图片描述

class Product{
  image:ResourceStr = ''  //图片
  title:string = '' //标题
  salesVolume:number = 0  //销售数量
  price:number = 0  //价格

  constructor(image: ResourceStr, title: string, salesVolume: number, price: number) {
    this.image = image
    this.title = title
    this.salesVolume = salesVolume
    this.price = price
  }
}

@Entry
@Component
struct Index {

  @State array:Product[] = [
    new Product($r('app.media.11'),"漫花无芯卷纸16卷*1提",1000,9.9),
    new Product($r('app.media.22'),"BuBBLE TREE 款式",200,19.9),
    new Product($r('app.media.33'),"爸爸妈妈器材风车玩具",100,7.9),
    new Product($r('app.media.44'),"曼花挂式洗脸巾50抽*3提",500,19.9)
  ]

  build() {
    Column() {
      List({space:10}){
        ForEach(this.array,(item:Product)=>{
          ListItem(){
            this.productListItem(item)
          }
        })
      }.padding(10)
    }.width("100%")
    .height("100%")
    .backgroundColor("#dedede")
  }

  @Builder
  productListItem(item: Product) {
    Row({ space: 10 }) {
      Image(item.image).width(100).height(100)
        .borderRadius(10)
      Column() {
        Text(item.title).fontSize(16)
        Text(item.salesVolume + "+售出").fontSize(12).fontColor(Color.Orange)
        Text("¥" + item.price + "元").fontWeight(FontWeight.Bold).fontSize(18).fontColor(Color.Red)
      }.layoutWeight(1)
      .alignItems(HorizontalAlign.Start)
    }
    .width("100%")
    .justifyContent(FlexAlign.Start)
    .alignItems(VerticalAlign.Center)
    .padding(10)
    .backgroundColor(Color.White)
    .borderRadius(10)
  }
}

编辑列表

编辑列表指的是新增、删除、更新列表项,这是对于列表常见的操作之一。下面以待办事项管理为例,介绍如何快速实现新增和删除列表项功能。

在这里插入图片描述

代码如下

//@ObservedV2 
@ObservedV2
class ToDo {
  name: string = '' //标题
  @Trace isCompleted: boolean = false //是否完成

  constructor(name: string, isCompleted?: boolean) {
    this.name = name
    this.isCompleted = isCompleted ?? false
  }
}

@Entry
@Component
struct Index {
  @State todoList: ToDo[] = [
    new ToDo("运动"),
    new ToDo("阅读")
  ]

  //代办选中的样式
  toDoCompletedStyle: DecorationStyleInterface = {
    type: TextDecorationType.LineThrough,
    color: Color.Red
  }

  build() {
    Column() {
      List({ space: 10 }) {
        ForEach(this.todoList, (item: ToDo, index: number) => {
          ListItem() {
            this.toDoListItem(item, index)
          }
        })
      }.padding(10)

      Button("添加代办")
        .onClick(() => {
          this.todoList.push(new ToDo("新任务"))
        })
    }.width("100%")
    .height("100%")
    .backgroundColor("#dedede")
  }

  @Builder
  toDoListItem(item: ToDo, index: number) {
    Row({ space: 10 }) {
      Checkbox().onChange((value: boolean) => {
        item.isCompleted = value
      })
      
      Text(item.name).fontSize(16).fontWeight(FontWeight.Bold)
        .decoration(item.isCompleted ? this.toDoCompletedStyle : undefined)

      Blank()

      Text('删除')
        .fontColor("#00aaff")
        .fontSize(14)
        .fontWeight(FontWeight.Bold)
        .onClick(() => {
          //从当前位置删除一个元素
          this.todoList.splice(index, 1)
        })
    }
    .width("100%")
    .height(50)
    .backgroundColor(item.isCompleted ? Color.Pink : Color.White)
    .borderRadius(15)
    .padding({ left: 10, right: 10 })
  }
}

对鸿蒙感兴趣的同学,免费考取鸿蒙开发者认证