ArkTS List 的简单应用

219 阅读10分钟

ArkTS List 的简单应用

在ArkTS中,List组件是一个非常重要的容器组件,用于展示一系列的项目或数据项。以下将介绍List组件的使用场景、注意事项及其子组件。

使用场景

1. 列表展示

  • 适用场景:List组件最适合用于展示数据列表,如商品列表、联系人列表、新闻列表等。这些列表通常包含多个相似的数据项,且每个数据项都需要以统一的方式展示。

2. 滚动视图

  • 适用场景:当列表项过多,无法在一屏内完全展示时,List组件可以配合滚动条使用,允许用户通过滚动来查看更多内容。这种交互方式非常适合于移动端应用,因为屏幕尺寸有限。

3. 动态数据更新

  • 特性:List组件支持动态数据更新,当数据源发生变化时,可以自动刷新列表内容,无需手动重新加载页面或组件。这使得List组件非常适合用于实时数据展示或数据频繁更新的场景。

4. 自定义布局和样式

  • 灵活性:List组件支持自定义列表项的布局和样式,可以通过设置不同的子组件和样式属性来实现个性化的列表展示效果。

注意事项

1. 性能优化

  • 建议:当列表项数量非常大时,需要注意性能优化。例如,可以使用虚拟列表技术来减少DOM节点的数量,提高渲染效率。同时,尽量避免在列表项的渲染过程中执行复杂的计算或数据操作,这些操作应该在数据准备阶段完成。

2. 数据绑定

  • 正确性:确保List组件的数据源与视图层正确绑定,以便在数据更新时能够自动刷新列表内容。注意数据绑定的方向和时机,避免不必要的重复渲染或数据不一致问题。

3. 交互体验

  • 增强体验:为List组件添加适当的交互效果,如点击事件、滑动事件等,以提升用户体验。同时,注意处理列表项的选中状态、高亮状态等交互反馈,确保用户能够清晰地感知到当前的操作状态。

4. 兼容性

  • 测试:在使用List组件时,需要注意其与不同版本HarmonyOS系统的兼容性。确保在目标设备上能够正常展示和交互。

5. 滚动控制

  • 控制行为:如果需要控制List组件的滚动行为(如滚动到指定位置、停止滚动等),可以使用List组件提供的滚动控制器(如ListScroller)来实现。

6. API版本

  • 更新关注:注意不同API版本之间List组件的差异和更新。随着HarmonyOS系统的不断升级,List组件的API和功能也可能会发生变化。因此,在开发过程中需要关注最新的API文档和更新日志。

List组件及其子组件

List

  • 参数
    • space:列表之间的间距。
    • initialIndex:设置当前List初次加载时视口起始位置显示的item的索引值,默认值为0。
    • scroller:绑定控制器(绑定的控制器只能有一个对象)
      • 控制列表滚动
  • 特点
    • 本身有较多的的监控事件 ,如onReachEnd list列表触底时触发。。。
    • 适合用于展示数据列表,如商品列表、联系人列表、新闻列表等。
    • 交互效果丰富,支持多态样式联动、字母表等。
    • 支持cachedCount懒加载。
    • 选中状态

ListItem

  • 特性:ListItem是List的子组件,用于展示列表中的每一项数据。

  • swipeAction:用于设置ListItem的划出组件,实现如删除、设置等交互操作。

    创建一个带有滑动删除功能的列表项组件

    列表项(ListItem)的交互设计常常需要考虑到用户操作的便捷性和直观性。如何使用HarmonyOS的ArkTS框架来创建一个带有滑动删除功能的列表项组件。我们将通过代码示例详细解释每个部分的作用,确保读者能够清晰地理解并应用这一功能。

    组件定义与状态管理

    首先,我们定义一个名为myListItem的组件,它使用@Entry@Component装饰器来标记这是一个入口组件。在组件内部,我们通过@State装饰器来定义组件的状态,这里有两个状态变量:arr是一个数字数组,用于存储列表项的数据;text1是一个字符串,用于显示与滑动删除操作相关的状态信息。

    @Entry  
    @Component  
    struct myListItem {  
      @State arr: number[] = [0, 1, 2, 3, 4]  
      @State text1: string = "未进入删除区域"  
      // ... 后续代码  
    }
    
    滑动删除动作的构建

    接下来,我们定义了一个swipeActionEnd方法,它返回一个Row组件,其中包含两个Button,分别用于“删除”和“设置”操作。这个方法将作为滑动删除动作的构建器使用。

    @Builder swipeActionEnd() {  
      Row() {  
        Button("删除")
            .margin(10)  
        Button("设置")
            .margin(10)  
      }  
      .padding(10)  
      .justifyContent(FlexAlign.SpaceEvenly)  
    }
    
    构建列表项与滑动删除逻辑

    build方法中,我们使用Column容器来组织整个组件的布局。首先,我们放置了一个List组件,并通过ForEach循环遍历arr数组中的每个元素,为每个元素创建一个ListItem

    build() {  
      Column() {  
        List({ space: 10 }) {  
          ForEach(this.arr, (item: number) => {  
            // ... ListItem 的定义与滑动删除逻辑  
          }, (item: string) => item)  
        }  
        // ... 其他布局与逻辑  
      }  
      // ... 布局样式设置  
    }
    

    ListItem内部,我们显示了一个文本,用于展示每个列表项的“唯一标识符”。此外,我们还为ListItem添加了过渡动效和滑动删除功能。

    • 过渡动效:当列表项被添加或删除时,通过.transition()方法设置过渡动效,这里使用的是Delete类型的动效,透明度逐渐变为0。
    • 滑动删除功能:通过.swipeAction()方法为ListItem设置滑动删除功能。我们定义了滑动结束时的组件(通过builder属性调用swipeActionEnd方法),以及滑动进入和退出删除区域时的状态更新(通过onEnterActionAreaonExitActionArea方法)。最重要的是,当用户完成滑动并抬起手指时,通过onAction方法执行删除操作,即从数组中移除对应的元素。
    ListItem() {  
      Text("唯一标识符:" + item)  
        // ... 文本样式设置  
    }  
    .transition({ type: TransitionType.Delete, opacity: 0 })  
    .swipeAction({  
      end: {  
        builder: () => { this.swipeActionEnd() },  
        onAction: () => {  
          // 删除操作  
        },  
        // ... 其他滑动删除设置  
      }  
    })
    

    最后,我们在组件的底部添加了一个文本显示区域,用于展示与滑动删除操作相关的状态信息(如是否已进入删除区域)。

    完整代码

    // xxx.ets
    @Entry
    @Component
    struct myListItem {
      @State arr: number[] = [0, 1, 2, 3, 4]
      @State text1: string = "未进入删除区域"
    
    
      @Builder swipeActionEnd() {
        Row() {
          Button("删除")
            .margin(10)
          Button("设置")
            .margin(10)
        }
        .padding(10)
        .justifyContent(FlexAlign.SpaceEvenly)
      }
    
      build() {
        Column() {
          List({ space: 10 }) {
            ForEach(this.arr, (item: number) => {
              ListItem() {
                Text("唯一标识符:" + item)
                  .width('100%')
                  .height(100)
                  .fontSize(16)
                  .textAlign(TextAlign.Center)
                  .borderRadius(10)
                  .backgroundColor('#fff')
              }
              //在组件插入和删除时显示过渡动效
              .transition({
                type: TransitionType.Delete,
                opacity: 0
              })
              //用于设置ListItem的划出组件
              .swipeAction({
                //设置左滑事件   start右滑事件
                end: {
                  //向左滑动显示的构造函数
                  builder: () => { this.swipeActionEnd() },
                  //进入长距删除区后抬手时触发  删除业务
                  onAction: () => {
                    animateTo({ duration: 1000 }, () => {
                      let index = this.arr.indexOf(item)
                      this.arr.splice(index, 1)
                    })
                  },
                  //设置组件长距离滑动删除距离阈值  默认值为56
                  actionAreaDistance: 56,
                  //进入删除区域时调用,只触发一次,当再次进入时仍触发
                  onEnterActionArea: () => {
                    this.text1 = "已滑入删除区域"
                  },
                  //退出删除区域时调用,只触发一次,当再次退出时仍触发
                  onExitActionArea: () => {
                    this.text1 = "未进入删除区域"
                  }
                }
              })
            }, (item: string) => item)
          }
          Text(this.text1).fontSize(20)
        }
        .padding(10)
        .backgroundColor('#ccc')
        .width('100%')
        .height('100%')
      }
    }
    

PixPin_2024-09-05_20-12-09.gif

通过以上步骤,我们成功创建了一个带有滑动删除功能的列表项组件。这个组件不仅提高了用户操作的便捷性,还通过动效和状态反馈增强了用户体验

ListItemGroup

  • 用途:List的分组组件,用于将列表项分组展示。

  • 子组件:只有ListItem。

  • 特性:支持设置头部(header)和尾部(footer)组件,用于展示分组标题和分组信息

    ListItemGroup组件构建课程表应用

    示例:展示如何使用ListItemGroup组件来创建一个课程表应用。通过ListItemGroup的分组功能,我们可以清晰地将每一天的课程按组显示,使得用户界面既美观又易于理解。

    定义课程表数据结构

    首先,我们需要定义一个课程表的数据结构。在鸿蒙开发中,通常使用interface来定义数据的类型。下面的TimeTable接口定义了一个课程表项的基本结构,包括课程的标题(title)和具体的课程项目(projects)列表。

    interface TimeTable {  
      title: string;  
      projects: string[];  
    }
    
    创建课程表组件

    接下来,我们创建一个名为ListItemGroupExample的组件,该组件将使用上面定义的数据结构来渲染课程表。

    ListItemGroupExample组件中,我们首先定义了一个名为timeTable的私有属性,这是一个TimeTable类型的数组,用于存储整个课程表的数据。

    private timeTable: TimeTable[] = [  
      // 示例数据:一周的课程表  
    ];
    
    自定义头部和尾部组件

    为了美化课程表的显示,我们还自定义了两个@Builder方法:itemHeaditemFoot,分别用于生成每个课程分组的头部和尾部组件。

    itemHead方法接受一个字符串参数作为课程标题,并返回一个具有特定样式(如字体大小、背景色等)的Text组件。

    itemFoot方法则显示课程组中课程的总数,也是通过Text组件来实现,并设置相应的样式。

    //构造函数
      @Builder
      itemHead(text: string) {
        Text(text)
          .fontSize(20)
          .backgroundColor('#aabbcb')
          .width("100%")
          .padding(10)
      }
    
      @Builder
      itemFoot(num: number) {
        Text('共' + num + "节课")
          .fontSize(16)
          .backgroundColor('#aabbcb')
          .width("100%")
          .padding(5)
      }
    
    使用ListItemGroup构建课程表

    build方法中,我们使用Column组件作为最外层的容器,然后通过List组件和ForEach循环来遍历timeTable数组,为每个课程日创建一个ListItemGroup

    每个ListItemGroup通过设置headerfooter属性来显示自定义的头部和尾部组件。内部再次使用ForEach循环遍历当天的课程项目,并为每个项目创建一个ListItem组件来显示课程名称。

    List({ space: 20 }) {  
      ForEach(this.timeTable, (item: TimeTable) => {  
        ListItemGroup({ header: this.itemHead(item.title), footer: this.itemFoot(item.projects.length) }) {  
          // 渲染课程项目  
        }  
        .divider({ // 分隔线样式  
          strokeWidth: 1,  
          color: Color.Blue  
        })  
      })  
    }  
    .width('90%')  
    .sticky(StickyStyle.Header | StickyStyle.Footer) // 设置粘性标题  
    .scrollBar(BarState.Off) // 隐藏滚动条
    

    最后,通过为ColumnList组件设置样式(如宽度、高度、背景色等),我们完成了整个课程表组件的构建。

    完整代码

    // xxx.ets
    
    //接口
    interface TimeTable {
      title: string;
      projects: string[];
    }
    
    @Entry
    @Component
    struct ListItemGroupExample {
      //自定义列表数据
      private timeTable: TimeTable[] = [
        {
          title: '星期一',
          projects: ['语文', '数学', '英语']
        },
        {
          title: '星期二',
          projects: ['物理', '化学', '生物']
        },
        {
          title: '星期三',
          projects: ['历史', '地理', '政治']
        },
        {
          title: '星期四',
          projects: ['美术', '音乐', '体育']
        }
      ]
    //构造函数
      @Builder
      itemHead(text: string) {
        Text(text)
          .fontSize(20)
          .backgroundColor('#aabbcb')
          .width("100%")
          .padding(10)
      }
    
      @Builder
      itemFoot(num: number) {
        Text('共' + num + "节课")
          .fontSize(16)
          .backgroundColor('#aabbcb')
          .width("100%")
          .padding(5)
      }
    
      build() {
        Column() {
          List({ space: 20 }) {
            ForEach(this.timeTable, (item: TimeTable) => {
              //ListItemGroup的分组功能
              //header 头部组件
              //footer 尾部组件
              ListItemGroup({ header: this.itemHead(item.title), footer: this.itemFoot(item.projects.length) }) {
                ForEach(item.projects, (project: string) => {
                  ListItem() {
                    Text(project)
                      .width("100%")
                      .height(100)
                      .fontSize(20)
                      .textAlign(TextAlign.Center)
                      .backgroundColor('#fff')
                  }
                }, (item: string) => item)
              }
              // 每行之间的分界线
              .divider({
                strokeWidth: 1,
                color: Color.Blue
              })
            })
          }
          .width('90%')
          //设置粘性标题  StickyStyle.Header  吸顶,StickyStyle.Footer  吸底
          .sticky(StickyStyle.Header | StickyStyle.Footer)
          //隐藏滚动条
          .scrollBar(BarState.Off)
        }
        .width('100%')
        .height('100%')
        .backgroundColor('#dcdcdc')
        .padding({ top: 5 })
      }
    }
    
    

PixPin_2024-09-05_20-44-20.gif

感谢各位开发者的阅读