一、List

1.概述

列表是一种非常有用且功能强大的容器,它常用于呈现同类型或多类型数据集合,例如图片、文本、音乐、通讯录、购物清单等。列表对于显示大量内容而不耗费过多空间和内存是非常有帮助的,因为当列表项数量超过屏幕大小时,可以自动提供滚动功能。这使得列表成为构建结构化、可滚动信息的理想容器。

使用列表可以轻松、高效地显示信息。使用List组件,可以按垂直或水平方向线性排列子组件,这些子组件可以是单个视图,也可以使用ForEach迭代一组行或列,或混合任意数量的单个视图和ForEach结构,构建一个灵活的列表。同时,List组件支持使用条件渲染、循环渲染、懒加载等渲染控制方式生成子组件,使得列表变得更加灵活和高效。

列表是一种非常实用的容器,适用于呈现各种类型的数据集合,并且可以为用户提供高效、流畅的滚动浏览体验。

2.布局与约束

ListItemGroup是一个用于列表数据分组展示的组件,它的子组件也是ListItem。

  • ListItem是单个列表项的表示,每个ListItem可以包含一个单独的子组件,用于更详细的展示该列表项的内容。

  • ListItemGroup可以通过增加、删除子组件或调整子组件的位置,来展示不同的分组数据。同时,你也可以扩展ListItem和ListItemGroup,添加更多的属性和方法,以适配不同的使用场景。

2.1 布局

1、垂直滚动列表

2、水平滚动列表(左:单行;右:多行)

2.2 约束

1、列表的主轴与交叉轴

如果List组件主轴或交叉轴方向设置了尺寸,则其对应方向上的尺寸为设置值。

2、一个垂直列表B没有设置高度时,其父组件A高度为200vp,若其所有子组件C的高度总和为150vp,则此时列表B的高度为150vp。

3、同样是没有设置高度的垂直列表B,其父组件A高度为200vp,若其所有子组件C的高度总和为300vp,则此时列表B的高度为200vp。

3.开发布局

3.1 设置主轴方向

List() {
...
}
.listDirection(Axis.Horizontal)

List组件默认主轴方向是垂直的,可以自动构建垂直滚动列表,无需手动设置。如果需要构建水平滚动列表,只需要将List组件的listDirection属性设置为Axis.Horizontal即可。需要注意的是,listDirection属性的默认值为Axis.Vertical,即默认情况下List组件的主轴方向是垂直方向。

更多鸿蒙最新技术知识点,请关注作者博客:https://t.doruo.cn/14DjR1rEY

3.2 设置交叉轴布局

List组件的交叉轴布局可以通过lanes和alignListItem属性进行设置。lanes属性用于确定交叉轴排列的列表项数量,alignListItem用于设置子组件在交叉轴方向的对齐方式。一般情况下,List组件的lanes属性被用于在不同尺寸的设备上自适应构建不同行数或列数的列表。lanes属性的取值类型为"number | LengthConstrain",即整数或者LengthConstrain类型。

List() {
...
}
.lanes(2)
List() {
...
}
.lanes({ minLength: 200, maxLength: 300 })
List() {
...
}
.alignListItem(ListItemAlign.Center)
  • lanes:设置列数
  • alignListItem:设置对齐方式

4.案例

4.1 在列表中显示数据

@Entry
@Component
struct Index {
build() {
List() {
ListItem() {
Text('北京').fontSize(24)
} ListItem() {
Text('杭州').fontSize(24)
} ListItem() {
Text('上海').fontSize(24)
}
}
.backgroundColor('#FFF1F3F5')
.alignListItem(ListItemAlign.Center)
}
}


@Entry
@Component
struct Index {
build() {
List() {
ListItem() {
Row() {
Image($r('app.media.app_icon'))
.width(40)
.height(40)
.margin(10) Text('小明')
.fontSize(20)
}
} ListItem() {
Row() {
Image($r('app.media.app_icon'))
.width(40)
.height(40)
.margin(10) Text('小红')
.fontSize(20)
}
}
}
}
}

4.1 迭代列表内容

import util from '@ohos.util';

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 Index {
private contacts = [
new Contact('小明', $r("app.media.app_icon")),
new Contact('小红', $r("app.media.app_icon")),
new Contact('张三', $r("app.media.app_icon")),
new Contact('李四', $r("app.media.app_icon")),
] 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 => item.key+item.name)
}
.width('100%')
}
}

4.3 自定义列表样式

️4.3.1 内容间距
List({ space: 10 }) {
...
}

️4.3.2 添加分隔线
List() {
...
}
.divider({
strokeWidth: 1,
startMargin: 60,
endMargin: 10,
color: '#ffe9f0f0'
})

️4.3.3 添加滚动条
List() {
...
}
.scrollBar(BarState.Auto)

️4.3.4 分组列表

1、直接手动分钟

@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
...
}
... ListItemGroup({ header: this.itemHead('B') }) {
// 循环渲染分组B的ListItem
...
}
...
}
}
}

2、遍历分组

contactsGroups: object[] = [
{
title: 'A',
contacts: [
new Contact('艾佳', $r('app.media.iconA')),
new Contact('安安', $r('app.media.iconB')),
new Contact('Angela', $r('app.media.iconC')),
],
},
{
title: 'B',
contacts: [
new Contact('白叶', $r('app.media.iconD')),
new Contact('伯明', $r('app.media.iconE')),
],
},
...
]
List() {
// 循环渲染ListItemGroup,contactsGroups为多个分组联系人contacts和标题title的数据集合
ForEach(this.contactsGroups, item => {
ListItemGroup({ header: this.itemHead(item.title) }) {
// 循环渲染ListItem
ForEach(item.contacts, contact => {
ListItem() {
...
}
}, item => item.key)
}
...
})
}

️4.3.5 添加粘性标题(官方)
@Component
struct ContactsList {
// 定义分组联系人数据集合contactsGroups数组
... @Builder itemHead(text: string) {
// 列表分组的头部组件,对应联系人分组A、B等位置的组件
Text(text)
.fontSize(20)
.backgroundColor('#fff1f3f5')
.width('100%')
.padding(5)
} build() {
List() {
// 循环渲染ListItemGroup,contactsGroups为多个分组联系人contacts和标题title的数据集合
ForEach(this.contactsGroups, item => {
ListItemGroup({ header: this.itemHead(item.title) }) {
// 循环渲染ListItem
ForEach(item.contacts, contact => {
ListItem() {
...
}
}, item => item.key)
}
...
})
}
.sticky(StickyStyle.Header) // 设置吸顶,实现粘性标题效果
}
}

image

️4.3.6 控制滚动位置(官方)
private listScroller: Scroller = new Scroller();
Stack({ alignContent: Alignment.BottomEnd }) {
// 将listScroller用于初始化List组件的scroller参数,完成listScroller与列表的绑定。
List({ space: 20, scroller: this.listScroller }) {
...
}
... Button() {
...
}
.onClick(() => {
// 点击按钮时,指定跳转位置,返回列表顶部
this.listScroller.scrollToIndex(0)
})
...
}

️4.3.7 响应滚动位置(官方)
...
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 = firstIndex
// 根据列表滚动到的索引值,重新计算对应联系人索引栏的位置this.selectedIndex
...
})
...
// 字母表索引组件
AlphabetIndexer({ arrayValue: alphabets, selected: 0 })
.selected(this.selectedIndex)
...
}
}
}

️4.3.8 响应列表项侧滑(官方)
@Entry
@Component
struct MessageList {
@State messages: object[] = [
// 初始化消息列表数据
...
]; @Builder itemEnd(index: number) {
// 侧滑后尾端出现的组件
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_public_delete_filled'))
.width(20)
.height(20)
}
.onClick(() => {
this.messages.splice(index, 1);
})
...
}
build() {
...
List() {
ForEach(this.messages, (item, index) => {
ListItem() {
...
}
.swipeAction({ end: this.itemEnd.bind(this, index) }) // 设置侧滑属性
}, item => item.id.toString())
}
...
}
}

️4.3.9 给列表项添加标记(官方)
Badge({
count: 1,
position: BadgePosition.RightTop,
style: { badgeSize: 16, badgeColor: '#FA2A2D' }
}) {
// Image组件实现消息联系人头像
...
}
...

️4.3.10 下拉刷新与上拉加载(官方)

案例:https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_NewsDataLoad?ha_linker=eyJ0cyI6MTcwMTY1Njg2NjU1MywiaWQiOiJjNDFjZDY5NTVjZDQ0NTBjZWE1ZWQxOTQ0MzZkODJkNSJ9

第三方组件:https://gitee.com/openharmony-sig/PullToRefresh

更多鸿蒙最新技术知识点,请关注作者博客:https://t.doruo.cn/14DjR1rEY

️4.3.11 编辑列表(官方)

1、定义列表项数据结构

import util from '@ohos.util';

export class ToDo {
key: string = util.generateRandomUUID(true);
name: string; constructor(name: string) {
this.name = name;
}
}

2、初始化数据

@State toDoData: ToDo[] = [];
private availableThings: string[] = ['读书', '运动', '旅游', '听音乐', '看电影', '唱歌'];

3、构建列表布局和列表项

List({ space: 10 }) {
ForEach(this.toDoData, (toDoItem) => {
ListItem() {
...
}
}, toDoItem => toDoItem.key)
}

4、响应用户确定新增事件,更新列表数据

Text('+')
.onClick(() => {
TextPickerDialog.show({
range: this.availableThings,
onAccept: (value: TextPickerResult) => {
this.toDoData.push(new ToDo(this.availableThings[value.index])); // 新增列表项数据toDoData
},
})
})

️4.3.12 删除列表项(官方)

1、以待办列表为例,通过监听列表项的长按事件,当用户长按列表项时,进入编辑模式。

// ToDoListItem.ets

Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
...
}
.gesture(
GestureGroup(GestureMode.Exclusive,
LongPressGesture()
.onAction(() => {
if (!this.isEditMode) {
this.isEditMode = true; //进入编辑模式
this.selectedItems.push(this.toDoItem); // 记录长按时选中的列表项
}
})
)
)

2、在待办列表中,通过勾选框的勾选或取消勾选,响应用户勾选列表项变化,记录所有选择的列表项。

// ToDoListItem.ets

if (this.isEditMode) {
Checkbox()
.onChange((isSelected) => {
if (isSelected) {
this.selectedItems.push(this.toDoItem) // 勾选时,记录选中的列表项
} else {
let index = this.selectedItems.indexOf(this.toDoItem)
if (index !== -1) {
this.selectedItems.splice(index, 1) // 取消勾选时,则将此项从selectedItems中删除
}
}
})
...
}

3、需要响应用户点击删除按钮事件,删除列表中对应的选项

// ToDoList.ets

Button('删除')
.onClick(() => {
// 删除选中的列表项对应的toDoData数据
let leftData = this.toDoData.filter((item) => {
return this.selectedItems.find((selectedItem) => selectedItem !== item);
}) this.toDoData = leftData;
this.isEditMode = false;
})
...

4.4 长列表的处理

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

当使用懒加载方式渲染列表时,为了更好的列表滚动体验,并减少列表滑动时出现白块,List组件提供了cachedCount参数。该参数用于设置列表项缓存数量,只在懒加载LazyForEach中生效。

List() {
LazyForEach(this.dataSource, item => {
ListItem() {
...
}
})
}.cachedCount(3)

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing,不定期分享原创知识。
  • 更多鸿蒙最新技术知识点,请关注作者博客:https://t.doruo.cn/14DjR1rEY

鸿蒙HarmonyOS实战-ArkUI组件(List)的更多相关文章

  1. 鸿蒙的远程交互组件应用及微信小程序的远程交互组件应用

    注:鸿蒙的远程交互组件应用相对复杂 ,访问网络时,首先要配置网络权限,华为官方文档有问题,在此引用我老师配置的模板,见附件 过程:1.导入鸿蒙的网络请求模块fetch 2.发起对服务器的请求(在这过程 ...

  2. 微信小程序入门与实战 常用组件API开发技巧项目实战*全

    第1章 什么是微信小程序? 第2章 小程序环境搭建与开发工具介绍 第3章 从一个简单的“欢迎“页面开始小程序之旅 第4章 第二个页面:新闻阅读列表 第5章 小程序的模板化与模块化 第6章 构建新闻详情 ...

  3. 手把手带你体验鸿蒙 harmonyOS

    wNlRGd.png 前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 image.png 一.为什么要尝鲜 harmonyos? wNlfx ...

  4. 最全华为鸿蒙 HarmonyOS 开发资料汇总

    开发 本示例基于 OpenHarmony 下的 JavaScript UI 框架,进行项目目录解读,JS FA.常用和自定义组件.用户交互.JS 动画的实现,通过本示例可以基本了解和学习到 JavaS ...

  5. 鸿蒙HarmonyOS应用开发落地实践,Harmony Go 技术沙龙落地北京

    12月26日,华为消费者BG软件部开源中心与51CTO Harmony OS技术社区携手,共同主办了主题为"Harmony OS 应用开发落地实践"的 Harmony Go 技术沙 ...

  6. 鸿蒙开源第三方件组件——轮播组件Banner

    目录: 1.功能展示 2.Sample解析 3.Library解析 4.<鸿蒙开源第三方组件>系列文章合集 前言 基于安卓平台的轮播组件Banner(https://github.com/ ...

  7. 14-Flutter移动电商实战-ADBanner组件的编写

    拨打电话的功能在app里也很常见,比如一般的外卖app都会有这个才做.其实Flutter本身是没给我们提供拨打电话的能力的,那我们如何来拨打电话那? 1.编写店长电话模块 这个小伙伴们一定轻车熟路了, ...

  8. 13-Flutter移动电商实战-ADBanner组件的编写

    1.AdBanner组件的编写 我们还是把这部分单独出来,需要说明的是,这个Class你也是可以完全独立成一个dart文件的.代码如下: 广告图片class AdBanner extends Stat ...

  9. iview实战 : 树形组件自定义

    Tree树形组件是 iview 中相对复杂的一个组件. 自定义节点内容 使用强大的 Render 函数可以自定义节点显示内容和交互,比如添加图标,按钮等. ——官方文档 但官方的 example 只有 ...

  10. ArkUI 组件 Props

    在上一篇博客文章中简单地提到了 Props . 在使用 Props 时需要注意到一个点,子组件从寄主页面传递过来的值是单向的,也就是子组件不能直接修改传递下来的值,即单向性. 以上篇文章定义的头像组件 ...

随机推荐

  1. 微信小程序获取本日、本周、本月、本年时间段

    原文链接 https://cslaoxu.vip/110.html 说明 最近需要用到统计不同时间段内的记录数,所以找了一下现成的工具类.下面就演示一下如何引用到实际项目中. 详细用法请参考:http ...

  2. OCP试题解析之053-16 MEMORY_TARGET

    16.Setting which of the following initialization parameters enables Automatic Memory Management? A. ...

  3. r0capture 原理分析

    r0capture 是比较好用的抓包工具 仅限安卓平台,测试安卓7.8.9.10.11.12 可用 : 无视所有证书校验或绑定,不用考虑任何证书的事情: 通杀TCP/IP四层模型中的应用层中的全部协议 ...

  4. GROW模型:世界上最常用的教练模型(**案例及全套表单)

    http://www.360doc.com/content/21/0812/18/76566468_990752480.shtml <高绩效教练>一书的核心方法就是GROW模型. GROW ...

  5. values_list()中参数flat用法

    先说下values from .models import Student student = Student.objects.values('number') student [{'number': ...

  6. [软件工程] CMMI是什么?

    序 能力成熟度模型集成(CMMI) 一.CMMI(能力成熟度模型集成)概述 CMMI是由美国软件工程学会(software engineering institue,简称SEI)制定的一套专门针对软件 ...

  7. MySQL基础3-数据库增删改操作

    一.SQL通用语法 SQL 语法可以单行或者多行书写,以分号结尾. SQL 语句可以使用空格/缩进来增强语句的可读性. MySQL 数据库的 SQL 语句不区分大小写,关键字建议使用大写. 注释: 单 ...

  8. TypeScript项目开发运行(即时编译、运行,所见所得)

    1.项目*.ts自动编译 $ tsc . --watch 2.项目本地web服务运行 $ npm install --save-dev webpack-dev-server npm install - ...

  9. [Python] 超简单的 超星学习通自动签到

    目录 概述 代码 其他的 文件编码问题 windows 和 linux下换行符不同的问题 概述 今天两节课的签到都错过了 /(ㄒoㄒ)/~~ 所以决定花点时间做一个自动签到的工具 经过观察发现超星的结 ...

  10. 彩虹猫IDA分析记录

    目录 彩虹猫分析 概述 无参启动 带/main参数启动 带/watchdog参数启动 MBR引导程序和动画程序 第一段 引导代码 第二段 动画代码 其他函数 扭曲桌面 扰乱鼠标 钩子函数 桌面绘制图标 ...