鸿蒙界面开发(九):列表布局 (List)

news2024/9/28 7:03:25

列表布局

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

布局与约束

列表作为一种容器,会自动按其滚动方向排列子组件,向列表中添加组件或从列表中移除组件会重新排列子组件。
ListItemGroup用于列表数据的分组展示,其子组件也是ListItem。ListItem表示单个列表项,可以包含单个子组件。
说明: List的子组件必须是ListItemGroup或ListItem,ListItem和ListItemGroup必须配合List来使用。

Grid和WaterFlow也可以实现单列、多列布局,如果布局每列等宽,且不需要跨行跨列布局,相比Gird和WaterFlow,则更推荐使用List。

  1. 如果List组件主轴或交叉轴方向设置了尺寸,则其对应方向上的尺寸为设置值。
  2. 如果List组件主轴方向没有设置尺寸,当List子组件主轴方向总尺寸小于List的父组件尺寸时,List 主轴方向尺寸自动适应子组件的总尺寸。如果List的子组件主轴方向总尺寸超过List的父组件尺寸时,List主轴方向尺寸适应List的父组件尺寸。
  3. List组件交叉轴方向在没有设置尺寸时,其尺寸默认自适应父组件尺寸

开发布局

设置主轴方向

List() { // ...}
.listDirection(Axis.Horizontal)
listDirection属性设置为Axis.Horizontal,水平滚动。
listDirection默认为Axis.Vertical,即主轴默认是垂直方向。

设置交叉轴布局

List组件的交叉轴布局可以通过lanes和alignListItem属性进行设置,
lanes属性用于确定交叉轴排列的列表项数量,
alignListItem用于设置子组件在交叉轴方向的对齐方式。

lanes

List组件的lanes属性通常用于在不同尺寸的设备自适应构建不同行数或列数的列表,即一次开发、多端部署的场景,例如歌单列表。
lanes属性的取值类型是"number | LengthConstrain",即整数或者LengthConstrain类型。
当其取值为LengthConstrain类型时,表示会根据LengthConstrain与List组件的尺寸自适应决定行或列数。

//取值为number
List() { // ...}
.lanes(2)
//取值为LengthConstrain类型
@Entry
@Component
struct EgLanes {
  @State egLanes: LengthConstrain = { minLength: 200, maxLength: 300 }
  build() {
    List() { // ...}
    .lanes(this.egLanes)
  }
}
当List组件宽度为300vp时,由于minLength为200vp,此时列表为一列。
当List组件宽度变化至400vp时,符合两倍的minLength,则此时列表自适应为两列。

alignListItem属性

默认值是ListItemAlign.Start,即列表项在列表交叉轴方向上默认按首部对齐。
ListItemAlign.Center表示列表项在水平方向上居中对齐。

List() { // ...}
.alignListItem(ListItemAlign.Center)

在列表中显示数据

ListItem中只能有一个根节点组件,若列表项是由多个组件元素组成的,则需要将这多个元素组合到一个容器组件内或组成一个自定义组件。

List() {
  ListItem() {
    Row() {
      Image($r('app.media.iconE'))
        .width(40)
        .height(40)
        .margin(10)

      Text('小明')
        .fontSize(20)
    }
  }
 }

迭代列表内容

通常,应用通过数据集合动态地创建列表。使用循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件,降低代码复杂度。

ArkTS通过ForEach提供了组件的循环渲染能力。

import { util } from '@kit.ArkTS'

class Contact {
  key: string = util.generateRandomUUID(true);
  name: string;
  icon: Resource;

  constructor(name: string, icon: Resource) {
    this.name = name;
    this.icon = icon;
  }
}

@Entry
@Component
struct SimpleContacts {
  private contacts: Array<object> = [
    new Contact('小明', $r("app.media.iconA")),
    new Contact('小红', $r("app.media.iconB")),
  ]

  build() {
    List() {
      ForEach(this.contacts, (item: Contact) => {
        ListItem() {
          Row() {
            Image(item.icon)
              .width(40)
              .height(40)
              .margin(10)
            Text(item.name).fontSize(20)
          }
          .width('100%')
          .justifyContent(FlexAlign.Start)
        }
      }, (item: Contact) => JSON.stringify(item))
    }
    .width('100%')
  }
}

自定义列表样式

设置内容间距——space参数

List({ space: 10 }) {
  // ...
}

添加分隔线——divider属性

divider属性用于给列表项之间添加分隔线。在设置divider属性时,可以通过strokeWidth和color属性设置分隔线的粗细和颜色。
startMargin和endMargin属性分别用于设置分隔线距离列表侧边起始端的距离和距离列表侧边结束端的距离。

class DividerTmp {
  strokeWidth: Length = 1
  startMargin: Length = 60
  endMargin: Length = 10
  color: ResourceColor = '#ffe9f0f0'

  constructor(strokeWidth: Length, startMargin: Length, endMargin: Length, color: ResourceColor) {
    this.strokeWidth = strokeWidth
    this.startMargin = startMargin
    this.endMargin = endMargin
    this.color = color
  }
}
@Entry
@Component
struct EgDivider {
  @State egDivider: DividerTmp = new DividerTmp(1, 60, 10, '#ffe9f0f0')
  build() {
    List() {// ... }
    .divider(this.egDivider)
  }
}

说明

分隔线的宽度会使ListItem之间存在一定间隔,当List设置的内容间距小于分隔线宽度时,ListItem之间的间隔会使用分隔线的宽度。

当List存在多列时,分割线的startMargin和endMargin作用于每一列上。

List组件的分隔线画在两个ListItem之间,第一个ListItem上方和最后一个ListItem下方不会绘制分隔线。

添加滚动条——scrollBar属性

在使用List组件时,可通过scrollBar属性控制列表滚动条的显示。scrollBar的取值类型为BarState,当取值为BarState.Auto表示按需显示滚动条。此时,当触摸到滚动条区域时显示控件,可上下拖拽滚动条快速浏览内容,拖拽时会变粗。若不进行任何操作,2秒后滚动条自动消失。

scrollBar属性API version 9及以下版本默认值为BarState.Off,从API version 10版本开始默认值为BarState.Auto。

List() { // ...}
.scrollBar(BarState.Auto)

支持分组列表——ListItemGroup

在List组件中使用ListItemGroup对项目进行分组,可以构建二维列表。
ListItemGroup的宽度默认充满List组件。在初始化ListItemGroup时,可通过header参数设置列表分组的头部组件。

@Entry
@Component
struct ContactsList {
  @Builder itemHead(text: string) {
    // 列表分组的头部组件,对应联系人分组A、B等位置的组件
    Text(text)
      .fontSize(20)
      .backgroundColor('#fff1f3f5')
      .width('100%')
      .padding(5)
  }

  build() {
    List() {
      ListItemGroup({ header: this.itemHead('A') }) {
        // 循环渲染分组A的ListItem
      }
    }
  }
}

添加粘性标题——sticky属性

粘性标题是一种常见的标题模式,常用于定位字母列表的头部元素。如在联系人列表中滚动A部分时,B部分开始的头部元素始终处于A的下方。而在开始滚动B部分时,B的头部会固定在屏幕顶部,直到所有B的项均完成滚动后,才被后面的头部替代。

List组件的sticky属性配合ListItemGroup组件使用,用于设置ListItemGroup中的头部组件是否呈现吸顶效果或者尾部组件是否呈现吸底效果。




设置sticky属性为StickyStyle.Header,即可实现列表的粘性标题效果。
如果需要支持吸底效果,可以通过footer参数初始化ListItemGroup的底部组件,并将sticky属性设置为StickyStyle.Footer。

ListItemGroup({ header: this.itemHead(itemGroup.title) }) {
         // 循环渲染ListItem
}.sticky(StickyStyle.Header)  // 设置吸顶,实现粘性标题效果

控制滚动位置

用户滚动列表到一定位置时,希望快速滚动到列表底部或返回列表顶部。此时,可以通过控制滚动位置来实现列表的快速定位。
List组件初始化时,可以通过scroller参数绑定一个Scroller对象,就可以通过Scroller对象的scrollToIndex方法使列表滚动到指定的列表项索引位置。

首先,需要创建一个Scroller的对象listScroller。

private listScroller: Scroller = new Scroller();

然后,通过将listScroller用于初始化List组件的scroller参数,完成listScroller与列表的绑定。在需要跳转的位置指定scrollToIndex的参数为0,表示返回列表顶部。

Stack({ alignContent: Alignment.Bottom }) {
  // 将listScroller用于初始化List组件的scroller参数,完成listScroller与列表的绑定。
  List({ space: 20, scroller: this.listScroller }) {
    // ...
  }

  Button() {
    // ...
  }
  .onClick(() => {
    // 点击按钮时,指定跳转位置,返回列表顶部
    this.listScroller.scrollToIndex(0)
  })
}

响应滚动位置

监听列表的滚动位置变化并作出响应
在这里插入图片描述

当联系人列表从A滚动到B时,右侧索引栏也需要同步从选中A状态变成选中B状态。此场景可以通过监听List组件的onScrollIndex事件来实现,右侧索引栏需要使用字母表索引组件AlphabetIndexer

在列表滚动时,根据列表此时所在的索引值位置firstIndex,重新计算字母索引栏对应字母的位置selectedIndex。由于AlphabetIndexer组件通过selected属性设置了选中项索引值,当selectedIndex变化时会触发AlphabetIndexer组件重新渲染,从而显示为选中对应字母的状态。

const alphabets = ['#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
@Entry
@Component
struct ContactsList {
  @State selectedIndex: number = 0;
  private listScroller: Scroller = new Scroller();

  build() {
    Stack({ alignContent: Alignment.End }) {
      List({ scroller: this.listScroller }) {}
      .onScrollIndex((firstIndex: number) => {
        // 根据列表滚动到的索引值,重新计算对应联系人索引栏的位置this.selectedIndex
      })

      // 字母表索引组件
      AlphabetIndexer({ arrayValue: alphabets, selected: 0 })
        .selected(this.selectedIndex)
    }
  }
}

说明
计算索引值时,ListItemGroup作为一个整体占一个索引值,不计算ListItemGroup内部ListItem的索引值。

响应列表项侧滑——swipeAction属性

给列表项添加标记——Badge组件

下拉刷新与上拉加载

编辑列表

新增列表项

删除列表项

长列表的处理——懒加载

循环渲染适用于短列表,当构建具有大量列表项的长列表时,如果直接采用循环渲染方式,会一次性加载所有的列表元素,会导致页面启动时间过长,影响用户体验。因此,推荐使用数据懒加载(LazyForEach)方式实现按需迭代加载数据,从而提升列表性能。

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

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

相关文章

【动态规划-多重背包】【hard】力扣2585. 获得分数的方法数

考试中有 n 种类型的题目。给你一个整数 target 和一个下标从 0 开始的二维整数数组 types &#xff0c;其中 types[i] [counti, marksi] 表示第 i 种类型的题目有 counti 道&#xff0c;每道题目对应 marksi 分。 返回你在考试中恰好得到 target 分的方法数。由于答案可能很…

mac 上配置Jmeter代理进行web脚本录制过程容易踩坑的点

macOS 配置 Jmeter代理录制web脚本&容易踩坑的点 mac配置下载&#xff1a;前景提要&#xff1a;Jmeter中具体操作容易踩坑的点1、进入浏览器后&#xff0c;显示访问连接不安全。2、证书失效需要重新生成3、重新生成证书的方式4、没有生成新的证书5、jmeter安装路径找不到 m…

数据库实验2—1

10-1 查询重量在[40,65]之间的产品信息 本题目要求编写SQL语句&#xff0c; 检索出product表中所有符合40 < Weight < 65的记录。 提示&#xff1a;请使用SELECT语句作答。 表结构: CREATE TABLE product (Pid varchar(20), --商品编号PName varchar(50), --商品名称…

因为穷,研究了一些备考软考高级「系分」的省钱方法!

有大学生留言&#xff1a;老师推荐我们考软考高级-系统分析师&#xff08;简称“系分”&#xff09;&#xff0c;但是对于大学生来说每次考证都好贵啊&#xff01;报名费、各种备考资料、视频课程、官方教程......七七八八加起来不少钱了。有没有钱包不痛备考软考高级的方法&am…

springboot集成nacos+gateway+feign

一、创建项目 1.创建一个maven项目 2.添加对应的pom参数 2.1添加工程对应的jar包 <!-- 父工程 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.7</…

如何有效评估与最大化利用专利价值?

专利价值评估是确定专利经济价值的关键环节。对于企业而言&#xff0c;准确评估专利价值可以帮助其做出明智的决策&#xff0c;如是否进行专利的投资、许可、转让等。同时&#xff0c;专利价值评估也为金融机构提供了重要的参考依据&#xff0c;有助于推动专利质押融资、证券化…

GetThreadSelectorEntry teb peb 段选择子 LDT_ENTRY _LDT_ENTRY

GetThreadSelectorEntry 函数原型 BOOL GetThreadSelectorEntry([in] HANDLE hThread,[in] DWORD dwSelector,[out] LPLDT_ENTRY lpSelectorEntry ); typedef struct _LDT_ENTRY {WORD LimitLow;WORD BaseLow;union {struct {BYTE BaseMid;BYTE Flags1;BYTE Fla…

Chroma 向量数据入门

Chroma 是 AI 原生的开源矢量数据库。Chroma 使知识、事实和技能可插入 LLM&#xff0c;从而可以轻松构建 LLM 应用程序。Chroma 是 AI 原生的开源矢量数据库。Chroma 使知识、事实和技能可插入 LLM&#xff0c;从而可以轻松构建 LLM 应用程序。 &#x1f31f;Chroma是一个文档…

WIN2008 iis安装与ASP设置

win2008 IIS安装在 Windows Server 2008 系统中安装IIS - morgan363 - 博客园 如何在 Windows Server 2008 系统中安装 IIS 呢&#xff1f;且看如下分解&#xff1a; 1、鼠标右键 “计算机”&#xff0c;选择“管理”&#xff0c;打开“服务器管理器”。 2、在“服务器管理器”…

【永磁同步电机(PMSM)】 3. 基于Matlab 的仿真与控制

【永磁同步电机&#xff08;PMSM&#xff09;】 3. 基于Matlab 的仿真与控制 1. 电机的仿真与控制2. BLDC 电机与 PMSM 电机3. BLDC 的方波控制4. 磁场定向控制&#xff08;FOC&#xff09;5. 空间矢量调制 (SVM)6. PMSM 模型的频率响应估计 电机仿真和控制是能源生产、汽车、航…

C语言贪吃蛇小游戏演示和说明

C语言贪吃蛇小游戏演示和说明 设计贪吃蛇游戏的主要目的是让大家夯实C语言基础&#xff0c;训练编程思维&#xff0c;培养解决问题的思路&#xff0c;领略多姿多彩的C语言。 游戏开始后&#xff0c;会在中间位置出现一条只有三个节点的贪吃蛇&#xff0c;并随机出现一个食物&am…

cpu路、核、线程、主频、缓存

路&#xff1a;主板插口实际插入的 CPU 个数&#xff0c;也可以理解为主板上支持的CPU的数量。每个CPU插槽可以插入一个物理处理器芯片。例如&#xff0c;一台服务器可能有2路或4路插槽&#xff0c;这意味着它最多可以安装2个或4个物理处理器。 核&#xff1a;单块 CPU 上面能…

代码随想录算法训练营第十四天|递归 226.翻转二叉树 101. 对称二叉树 104.二叉树的最大深度 111.二叉树的最小深度

226.翻转二叉树 翻转一棵二叉树。 思路&#xff1a; 在这里需要注意的是&#xff0c;在递归的时候唯独中序遍历是不可用的&#xff0c;这是因为先对左子树进行了反转&#xff0c;又对自身进行了反转&#xff0c;对自身反转后原本的左子树变成了右子树&#xff0c;如果此时又轮…

npm依赖安装的时候vue版本号报错处理

以下报错显示vue版本不对&#xff0c;需要改成这个版本"vue": "2.6.14"对应的版本 先看一下package.json中vue版本是多少 解决&#xff1a; npm install vue2.6.14

【重要提示】由于找不到msvcr110.dll 无法继续执行的解决途径全面解析

在使用Windows操作系统时&#xff0c;您可能会遇到这样的问题&#xff1a;某些应用程序在启动时提示“由于找不到 msvcr110.dll&#xff0c;无法继续执行代码。重新安装程序可能会解决此问题。” 这种错误通常会导致应用程序无法正常运行&#xff0c;影响用户体验。本文将全面介…

django开发流程1

一、官方网站&#xff1a; Django documentation | Django documentation | Djangohttps://docs.djangoproject.com/en/5.1/ 1.安装 django : pip install django 2. django项目的配置文件 (settings.py) BASE_DIR 项目根路径 DEBUG 调试模式 INSTALLE…

如何在算家云搭建CodeFormer(照片修复)

一、CodeFormer简介 CodeFormer 是一款强大的人工智能工具&#xff0c;专为处理低质量、损坏或模糊的面部图像而设计&#xff0c;主要用于图像和视频的修复和增强。它基于深度学习技术&#xff0c;通过先进的生成对抗网络&#xff08;GAN&#xff09;和自监督学习技术&#xf…

【LeetCode热题100】模拟

这篇博客记录了模拟相关的题目&#xff0c;也就是按照题目的描述写代码&#xff0c;很锻炼代码实现能力&#xff0c;包括了替换所有的问号、Z字形变换、外观数列、数青蛙4道题。 class Solution { public:string modifyString(string s) {int n s.size();for(int i 0 ; i <…

《数据结构与算法之美》学习笔记五之队列

前情提要&#xff1a;上一章学习了栈相关的知识&#xff0c;主要有下面的内容&#xff1a; 栈操作的时间复杂度&#xff0c;对于顺序栈&#xff0c;入栈时如果栈的空间不够涉及到数据搬移&#xff0c;此时使用摊还分析法&#xff0c;将数据搬移的耗时均摊到不需要搬移数据的入…

DeFi强势回归:新一轮DeFi牛市即将到来?

自2020年夏天的“DeFi之夏”以来&#xff0c;去中心化金融&#xff08;DeFi&#xff09;一直是加密行业的关键组成部分。“DeFi之夏”不仅将去中心化金融概念带入了实践&#xff0c;而且极大地推动了DeFi协议和应用的爆发式增长。尽管之后的市场经历了周期性的调整&#xff0c;…