写给初学者的 HarmonyOS 教程 -- ArkTS 容器组件(List)
使用列表可以轻松高效地显示结构化、可滚动的信息。通过在 List 组件中按垂直或者水平方向线性排列子组件 ListItemGroup 或 ListItem,为列表中的行或列提供单个视图,或使用ForEach 迭代一组行或列,或混合任意数量的单个视图和 ForEach 结构,构建一个列表。
ArkTS 框架采用 List 容器创建列表(类似 Android 的 RecycleView、Compose 的 LazyColumn)。
使用列表可以轻松高效地显示结构化、可滚动的信息。通过在 List 组件中按垂直或者水平方向线性排列子组件 ListItemGroup 或 ListItem,为列表中的行或列提供单个视图,或使用ForEach 迭代一组行或列,或混合任意数量的单个视图和 ForEach 结构,构建一个列表。
一、布局和约束
列表作为一种容器,会自动按其滚动方向排列子组件,向列表中添加组件或从列表中移除组件会重新排列子组件。
如下图所示,在垂直列表中,List 按垂直方向自动排列 ListItemGroup 或 ListItem。
ListItemGroup 用于列表数据的分组展示,其子组件也是 ListItem。ListItem 表示单个列表项,可以包含单个子组件。
List的子组件必须是 ListItemGroup 或 ListItem,ListItem 和 ListItemGroup 必须配合 List 来使用。
二、 静态创建
List 静态地创建其列表项 ListItem 的内容:
@Component
struct ListTest {
build() {
List() {
ListItem() {
Text("Kotlin").fontSize(10)
}
ListItem() {
Text("TypeScript").fontSize(10)
}
ListItem() {
Text("ArkTS").fontSize(10)
}
}
.backgroundColor('#FFF1F3F5')
.alignListItem(ListItemAlign.Center)
}
}
我们可以丰富一下 ListItem,给它加上图标:
@Component
struct ListTest {
build() {
List() {
ListItem() {
Row() {
Image($r('app.media.icon')).width(20).height(20).margin(10)
Text("Kotlin").fontSize(10)
}
}
ListItem() {
Row() {
Image($r('app.media.icon')).width(20).height(20).margin(10)
Text("TypeScript").fontSize(10)
}
}
ListItem() {
Row() {
Image($r('app.media.icon')).width(20).height(20).margin(10)
Text("ArkTS").fontSize(10)
}
}
}
.backgroundColor('#FFF1F3F5')
.alignListItem(ListItemAlign.Start)
}
}
三、循环渲染
一个列表项这么创建好了,但是我们可以发现 ListItem 内部的代码结构是一模一样的,这样写会显得代码很臃肿。
ListItem() {
Row() {
Image($r('app.media.icon')).width(20).height(20).margin(10)
Text("Kotlin").fontSize(10)
}
}
ListItem() {
Row() {
Image($r('app.media.icon')).width(20).height(20).margin(10)
Text("TypeScript").fontSize(10)
}
}
ListItem() {
Row() {
Image($r('app.media.icon')).width(20).height(20).margin(10)
Text("ArkTS").fontSize(10)
}
}
ArkTS 通过 ForEach 提供了组件的循环渲染能力。我们可以使用 ForEach,在其中以嵌套 ListItem 的形式来代替多个平铺的、内容相似的 ListItem,从而减少重复代码。如果对于 ForEach 不了解,可以查看 【 写给初学者的 HarmonyOS 教程 – 循环渲染(ForEach)】,了解其用法。
import util from '@ohos.util';
class Language {
key: string = util.generateRandomUUID(true);
icon: Resource;
name: string;
constructor(icon: Resource, name: string) {
this.icon = icon;
this.name = name;
}
}
@Entry
@Component
struct ListTest {
private devLanguages = [
new Language($r("app.media.icon"), 'Kotlin'),
new Language($r("app.media.icon"), 'TypeScript'),
new Language($r('app.media.icon'), 'ArkTS')
]
build() {
List() {
ForEach(this.devLanguages, (item: Language) => {
ListItem() {
Row() {
Image(item.icon).width(20).height(20).margin(10)
Text(item.name).fontSize(10)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
})
}
.backgroundColor('#FFF1F3F5')
.alignListItem(ListItemAlign.Start)
}
}
四、自定义列表样式
> 列表项间距
在初始化列表时,可以使用 space 参数添加列表项的间距。例如,在每个列表项之间沿主轴方向添加 30vp 的间距:
build() {
List({ space: 30 }) {
ForEach(this.devLanguages, (item: Language) => {
... ...
})
}
}
> 添加分割线
List 提供了divider 属性用于给列表项之间添加分隔线。
List({ space: 30 }) {
ForEach(this.devLanguages, (item: Language) => {
ListItem() {
Row() {
Image(item.icon).width(20).height(20).margin(10)
Text(item.name).fontSize(10)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
})
}
.divider({
strokeWidth: 1, // 分割线粗细
startMargin: 40, // 分隔线距离列表侧边起始端的距离
endMargin: 10, // 分隔线距离列表侧边结束端的距离
color: '#ff085DFF' // 分割线颜色
})
效果:
> 添加滚动条
实际 UI 界面可能会有很多列表项,超出屏幕后我们就需要添加滚动条,让用户可以滚动屏幕。比如我们再多添加几个语言:
private devLanguages = [
new Language($r("app.media.icon"), 'Kotlin'),
new Language($r("app.media.icon"), 'TypeScript'),
new Language($r('app.media.icon'), 'ArkTS'),
new Language($r('app.media.icon'), 'Python'),
new Language($r('app.media.icon'), 'Java'),
new Language($r('app.media.icon'), 'JavaScript'),
new Language($r('app.media.icon'), 'C++'),
new Language($r('app.media.icon'), 'C#'),
new Language($r('app.media.icon'), 'Ruby'),
new Language($r('app.media.icon'), 'Swift'),
new Language($r('app.media.icon'), 'Go'),
new Language($r('app.media.icon'), 'PHP'),
new Language($r('app.media.icon'), 'Flutter'),
new Language($r('app.media.icon'), 'R'),
]
这个时候一个屏幕塞不下这么多列表项,我们可以通过 List 的 scrollBar 属性控制列表滚动条的显示。
scrollBar 的取值类型为 BarState,当取值为 BarState.Auto 表示按需显示滚动条。此时,当触摸到滚动条区域时显示控件,可上下拖拽滚动条快速浏览内容,拖拽时会变粗。若不进行任何操作,2秒后滚动条自动消失。
List() {
...
}
.scrollBar(BarState.Auto)
效果:
五、分组列表
所谓分组列表,就是给列表项分组,比如联系人列表就是分组列表。
在 List 组件中使用 ListItemGroup 对项目进行分组,可以构建二维列表。
在 List 组件中可以直接使用一个或者多个 ListItemGroup 组件,ListItemGroup 的宽度默认充满 List 组件。在初始化ListItemGroup 时,可通过 header 参数设置列表分组的头部组件。
@Component
struct ListTest {
@Builder itemHead(text: string) {
// 列表分组的头部组件
Text(text)
.fontSize(10)
.backgroundColor('#fff1f3f5')
.width('100%')
.padding(5)
}
private devLanguages1 = [
new Language($r("app.media.icon"), 'Kotlin'),
new Language($r("app.media.icon"), 'TypeScript'),
new Language($r('app.media.icon'), 'ArkTS'),
new Language($r('app.media.icon'), 'Python'),
]
private devLanguages2 = [
new Language($r('app.media.icon'), 'Java'),
new Language($r('app.media.icon'), 'JavaScript'),
new Language($r('app.media.icon'), 'C++'),
new Language($r('app.media.icon'), 'C#'),
]
build() {
List() {
ListItemGroup( { header: this.itemHead( '开发语言 1')}) {
// 循环渲染分组 开发语言 1 的 ListItem
ForEach(this.devLanguages1, (item: Language) => {
ListItem() {
Row() {
Image(item.icon).width(20).height(20).margin(10)
Text(item.name).fontSize(10)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
})
}
.divider({
strokeWidth: 1,
startMargin: 40,
endMargin: 10,
color: '#ff085DFF'
})
ListItemGroup( { header: this.itemHead( '开发语言 2')}) {
// 循环渲染分组 开发语言 2 的 ListItem
ForEach(this.devLanguages2, (item: Language) => {
ListItem() {
Row() {
Image(item.icon).width(20).height(20).margin(10)
Text(item.name).fontSize(10)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
})
}
.divider({
strokeWidth: 1,
startMargin: 40,
endMargin: 10,
color: '#ff085DFF'
})
}
.backgroundColor('#FFF1F3F5')
.alignListItem(ListItemAlign.Start)
}
}
效果:
如果多个 ListItemGroup 结构类似,可以将多个分组的数据组成数组,然后使用 ForEach 对多个分组进行循环渲染。
@Component
struct ListTest {
@Builder itemHead(text: string) {
// 列表分组的头部组件
Text(text)
.fontSize(10)
.backgroundColor('#fff1f3f5')
.width('100%')
.padding(5)
}
languagesGroups: object[] = [
{
title: '开发语言 1',
languages: [
new Language($r("app.media.icon"), 'Kotlin'),
new Language($r("app.media.icon"), 'TypeScript'),
new Language($r('app.media.icon'), 'ArkTS'),
new Language($r('app.media.icon'), 'Python'),
],
},
{
title: '开发语言 2',
languages: [
new Language($r('app.media.icon'), 'Java'),
new Language($r('app.media.icon'), 'JavaScript'),
new Language($r('app.media.icon'), 'C++'),
new Language($r('app.media.icon'), 'C#'),
],
}
]
build() {
List() {
// 循环渲染 ListItemGroup,languagesGroups 为多个分组开大语言 languages 和标题 title 的数据集合
ForEach(this.languagesGroups, item => {
ListItemGroup({ header: this.itemHead(item.title) }) {
// 循环渲染 ListItem
ForEach(item.languages, language => {
ListItem() {
Row() {
Image(language.icon).width(20).height(20).margin(10)
Text(language.name).fontSize(10)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
})
}
.divider({
strokeWidth: 1,
startMargin: 40,
endMargin: 10,
color: '#ff085DFF'
})
})
}
.backgroundColor('#FFF1F3F5')
.alignListItem(ListItemAlign.Start)
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)