2.7、创建列表(List)

news2024/9/20 9:32:47

概述

列表是一种复杂的容器,当列表项达到一定数量,内容超过屏幕大小时,可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集,例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求(如通讯录、音乐列表、购物清单等)。

使用列表可以轻松高效地显示结构化、可滚动的信息。通过在List组件中按垂直或者水平方向线性排列子组件ListItemGroup或ListItem,为列表中的行或列提供单个视图,或使用ForEach迭代一组行或列,或混合任意数量的单个视图和ForEach结构,构建一个列表。List组件支持使用条件渲染、循环渲染、懒加载等渲染控制方式生成子组件。

我开发的 Demo 展示

在这里插入图片描述

以下代码均经过我 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);
  }
}

上一篇 2.6、媒体查询(mediaquery)
下一篇 2.8、下拉刷新与上拉加载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1544709.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享全栈开发医疗小程序 -带源码课件(课件无解压密码),自行速度保存

课程介绍 分享全栈开发医疗小程序 -带源码课件&#xff08;课件无解压密码&#xff09;&#xff0c;自行速度保存&#xff01;看到好多坛友都在求SpringBoot2.X Vue UniAPP&#xff0c;全栈开发医疗小程序 - 带源码课件&#xff0c;我看了一下&#xff0c;要么链接过期&…

SpringBoot集成Solr全文检索

SrpingBoot 集成 Solr 实现全文检索 一、核心路线 使用 Docker 镜像部署 Solr 8.11.3 版本服务使用 ik 分词器用于处理中文分词使用 spring-boot-starter-data-solr 实现增删改查配置用户名密码认证使用 poi 和 pdfbox 组件进行文本内容读取文章最上方有源码和 ik 分词器资源…

pe启动盘破解windows密码wins电脑登录密码修改重置

目录 1.进入电脑BIOS&#xff0c;设置电脑第一启动项为U盘启动2.进入微pe系统3.然后点击界面最左下方的Windows图标4.点击windows密码选择对应用户名称修改&#xff1b; 1.进入电脑BIOS&#xff0c;设置电脑第一启动项为U盘启动 把u盘插到要清除密码的电脑&#xff0c;然后开机…

面试八股——Redis——分布式锁——Redisson

1.看门狗机制 注意看门狗机制&#xff1a;redisson会监听持有锁的线程&#xff0c;并每隔一段时间(releaseTime/3&#xff0c;默认releaseTime为30s)&#xff0c;如果线程还未释放锁的话&#xff0c;会给锁做一次续期。 2. 主从一致性 实际开发中我们会搭建多台redis服务器&a…

【数据结构】非线性结构——二叉树

文章目录 前言1.树型结构1.1树的概念1.2树的特性1.3树的一些性质1.4树的一些表示形式1.5树的应用2.二叉树 2.1 概念2.2 两种特殊的二叉树2.3 二叉树的性质2.4 二叉树的存储2.5 二叉树的基本操作 前言 前面我们都是学的线性结构的数据结构&#xff0c;接下来我们就需要来学习非…

安防监控视频汇聚平台EasyCVR在银河麒麟V10系统中的启动异常及解决方法

安防监控视频平台EasyCVR具备较强的兼容性&#xff0c;它可以支持国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议与SDK&#xff0c;如&#xff1a;海康ehome、海康sdk、大华sdk、宇视sdk、华为sdk、萤石云sdk、乐橙sdk等。平台兼容性强&#xff0c;支持Windows系…

密码学及其应用1 —— 密码学概述

1 密码学的基本概念 1.1 网络安全的定义 网络安全是网络领域的一个专业领域&#xff0c;它涵盖了在基础计算机网络基础设施中所采取的措施、网络管理员为保护网络及网络可访问资源免受未授权访问而采纳的政策&#xff0c;以及对其有效性&#xff08;或无效性&#xff09;的持续…

WSL2 设置桥接模式

文章目录 一、前言二、准备阶段三、环境配置3.1 Type-V管理器环境配置3.2 新增.wslconfig 文件 四、遇到的问题以及解决方案 一、前言 ​ 使用 wsl 的过程中&#xff0c;会出现 WSL 的IP地址 找不到&#xff0c;或者无法和计算机通讯&#xff0c;搞 嵌入式 的话&#xff0c;还…

基于nodejs+vue智能菜谱推荐系统python-flask-django-php

本文拟采用nodejs技术和express 搭建系统框架&#xff0c;后台使用MySQL数据库进行信息管理&#xff0c;设计开发的智能菜谱推荐系统。通过调研和分析&#xff0c;系统拥有管理员和用户两个角色&#xff0c;主要具备登录注册、个人信息修改、对用户管理、类型管理、菜谱信息管理…

力扣算题【第二期】

文章目录 1.反转链表1.1 算法题目1.2 算法思路1.3 代码实现 2.回文链表2.1 算法题目2.2 算法思路2.3 代码实现 1.反转链表 1.1 算法题目 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 1.2 算法思路 1.设置工作指针p,来遍历链表。 2.采…

常用中间件redis,kafka及其测试方法

常用消息中间件及其测试方法 一、中间件的使用场景引入中间件的目的一般有两个&#xff1a;1、提升性能常用的中间件&#xff1a;1) 高速缓存&#xff1a;redis2) 全文检索&#xff1a;ES3) 存日志&#xff1a;ELK架构4) 流量削峰&#xff1a;kafka 2、提升可用性产品架构中高可…

我在京东做数据分析,一位京东数据分析师的工作日常

有人说&#xff1a;“种下一棵树最好的时间是十年前&#xff0c;其次是现在”。任何时候&#xff0c;我们都应该抓住机遇&#xff0c;说不定就是改变你现状的一个机会。 2020年&#xff0c;我在疫情得到控制后&#xff0c;面试入职京东大数据组&#xff0c;截止目前&#xff0…

elasticsearch+kibana安装部分问题:

1.elasticsearch启动问题&#xff1a; 如果elasticsearch开启https登录则第一次启动的时候需要前台启动&#xff0c;前台启动的时候会自己创建相应的token等登录信息,如果是后台启动则没有这些登录信息&#xff1a; ./elasticsearch ━━━━━━━━━━━━━━━━━━━…

web前端之3D标签动画、指定范围的随机数、动态设置css变量、文档片段对象、反向动画

MENU 效果图htmlJavaScriptstyle 效果图 html <div class"container"></div>JavaScript // 祝词 var words [健康码常绿,股票飙红,生意兴隆,财源广进,心想事成,永远十八,身体健康,大富大贵,大吉大利,万事如意,美梦成真,吉祥如意,鸿运当头,五福临门,吉…

flask_restful规范返回值之类型设置

大型的互联网项目中&#xff0c;返回的数据格式&#xff0c;有时是比较复杂的结构。 如&#xff1a;豆瓣电影 https://movie.douban.com/j/chart/top_list?type24&interval_id 100%3A90&action&start20&limit20 返回的值里有 json 或者列表数据&#xff0c…

HC-RS04超声波模块测速

1.硬件接线 电源3.3v~5v; 一个触发信号&#xff0c;3.3伏20us的脉冲。 一个接收&#xff0c;为脉冲的宽度&#xff0c;也就是高电平时间。 2.距离计算 距离音速x时间/2&#xff1b; D340m/s *Th /2,Th:为高电平时间。 距离范围&#xff1a;2~400cm 代码比较简单&#xff0c;就…

第十二届蓝桥杯物联网试题(省赛)

思路&#xff1a; 这个考了一个RTC的配置&#xff0c;RTC我只配过一次&#xff0c;所以有些生疏&#xff0c;还是不能大意&#xff0c;一些偏僻的考点还是要多练&#xff0c;在获取RTC时间的时候也遇到一些bug,这个后续会用一篇博客将最近遇到的BUG都总结一下 主要的难点还是…

RPA-财务对账邮件应用自动化(客户对账机器人)

《财务对账邮件应用自动化》&#xff0c;将会使用邮箱的SMTP服务&#xff0c;小北把资源包绑定在这篇博客了 Uibot (RPA设计软件)———机器人的小项目友友们可以参考小北的课前材料五博客~ (本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~&#xff09; …

Knative 助力 XTransfer 加速应用云原生 Serverless 化

作者&#xff1a;元毅 公司介绍 XTransfer 是一站式外贸企业跨境金融和风控服务公司&#xff0c;致力于帮助中小微企业大幅降低全球展业的门槛和成本&#xff0c;提升全球竞争力。公司连续7年专注 B2B 外贸金融服务&#xff0c;已成为中国 B2B 外贸金融第一平台&#xff0c;目…

服务端应用多级缓存架构方案

服务端应用多级缓存架构方案 场景 20w的QPS的场景下&#xff0c;服务端架构应如何设计&#xff1f; 常规解决方案 可使用分布式缓存来抗&#xff0c;比如redis集群&#xff0c;6主6从&#xff0c;主提供读写&#xff0c;从作为备&#xff0c;不提供读写服务。1台平均抗3w并…