阿里云服务器使用教程,seo1网站查询,网站开发商城,定制网站建设基础步骤List列表组件#xff0c;是一个非常常用的组件。可以说在一个应用中#xff0c;它的身影无处不在。它包含一系列相同宽度的列表项#xff0c;适合连续、多行呈现同类数据#xff0c;如商品列表、图片列表和和文本列表等。ArkUI 框架采用 List 容器组件创建列表#xff08;… List列表组件是一个非常常用的组件。可以说在一个应用中它的身影无处不在。它包含一系列相同宽度的列表项适合连续、多行呈现同类数据如商品列表、图片列表和和文本列表等。ArkUI 框架采用 List 容器组件创建列表类似 Android 的 RecycleView、Compose 的 LazyColumn。 之所以称List列表组件比较重磅一方面是因为它很常用另一方面是因为一旦学会了它其他组件也自然不在话下。有了它配合数据的加持可以让你的应用有模有样。类比下 Android 中的 RecycleView它的地位足够重要吧。
网上介绍 ArkUI 的List组件知识都太零碎且不够深入和系统。这里以一个任务列表页的完整实现为例详细介绍下List组件的使用、组件间的值的传递及项目代码的MVVM结构划分。分享给有需要的小伙伴喜欢的可以点下关注并收藏。
List组件介绍
List容器组件是一种常用的布局容器它主要用于展示一系列数据项这些数据项可以是同类型或不同类型的数据集合。List组件能够自动管理其内部子元素的复用和滚动行为非常适合构建列表界面例如商品列表联系人列表、消息列表等可以轻松高效地显示结构化、可滚动的信息。
通过在 List 组件中按垂直或者水平方向线性排列子组件 ListItemGroup 或 ListItem为列表中的行或列提供单个视图。或使用ForEach 迭代一组行或列或混合任意数量的单个视图和 ForEach 结构构建一个列表。注意List的子组件必须是 ListItemGroup 或 ListItemListItem 和 ListItemGroup 也必须配合 List 来使用。
如下图所示的两个页面
第一个页面中使用了Swiper容器组件实现的轮播图紧接着往下是使用的Grid网格容器组件最下方是Tabs组件。右侧图片则是List容器组件配合Scroll组件以及LazyForEach组件实现一个商品列表的页面并且拥有下拉刷新、懒加载和到底提示的效果。 一个简单的示例
List下用ForEach循环数据列表子项用ListItem组件组件中再设置布局。divider属性设置列表分割线listDirection属性设置列表是横向排列还是纵向排列(默认纵向)。 import router from ohos.routerEntry
Component
struct Index {private arr: number[] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]build() {Row() {Column() {List({ space: 10 }) {ForEach(this.arr, (item: number) {ListItem() {Text(${item}).width(100%).height(100).fontSize(20).fontColor(Color.White).textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0x007DFF).onClick(() {if (item 0) {//跳转到GridPage页面router.push({url: pages/GridPage})}})}}, item item)}//strokeWidth: 分割线的线宽。//color: 分割线的颜色。//startMargin分割线距离列表侧边起始端的距离。//endMargin: 分割线距离列表侧边结束端的距离。// .divider({// strokeWidth: 1,// color: Color.Gray,// startMargin: 10,// endMargin: 10// })//Vertical默认值子组件ListItem在List容器组件中呈纵向排列。//子组件ListItem在List容器组件中呈横向排列。.listDirection(Axis.Vertical)}.padding(12).height(100%).backgroundColor(0xF1F3F5)}.height(100%)}
}
通过 ForEach 提供了组件的循环渲染能力。我们可以使用 ForEach在其中以嵌套 ListItem 的形式来代替多个平铺的、内容相似的 ListItem从而减少重复代码。
上述示例显示的有些单调但是够基础。我们可以丰富一下 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)}
}List列表滚动事件监听
List组件提供了一系列事件方法用来监听列表的滚动您可以根据需要监听这些事件来做一些操作
onScroll列表滑动时触发返回值scrollOffset为滑动偏移量scrollState为当前滑动状态。onScrollIndex列表滑动时触发返回值分别为滑动起始位置索引值与滑动结束位置索引值。onReachStart列表到达起始位置时触发。onReachEnd列表到底末尾位置时触发。onScrollStop列表滑动停止时触发。
使用示例代码如下
List({ space: 10 }) {ForEach(this.arr, (item) {ListItem() {Text(${item})...}}, item item)
}
.onScrollIndex((firstIndex: number, lastIndex: number) {console.info(first firstIndex)console.info(last lastIndex)
})
.onScroll((scrollOffset: number, scrollState: ScrollState) {console.info(scrollOffset scrollOffset)console.info(scrollState scrollState)
})
.onReachStart(() {console.info(onReachStart)
})
.onReachEnd(() {console.info(onReachEnd)
})
.onScrollStop(() {console.info(onScrollStop)
})List使用详解
以下内容举例实现下图中的任务列表展示详细介绍下List组件的使用。 任务列表页
在pages目录下创建TaskListPage.ets文件。任务列表页由上部分的标题、返回按钮以及正中间的任务列表组成。使用Navigation以及List组件构成元素使用ForEach遍历生成具体列表。大致内容如下
// TaskListPage.ets
Navigation() {Column() {// 页面中间的列表TaskList()}.width(Const.THOUSANDTH_1000).justifyContent(FlexAlign.Center)
}
.size({ width: Const.THOUSANDTH_1000, height: Const.THOUSANDTH_1000 })
.title(Const.ADD_TASK_TITLE)
.titleMode(NavigationTitleMode.Mini)
TaskListComponent组件
TaskListPage中使用了自定义的TaskList()列表组件。由于TaskList是一个自定义的视图组件所以放在view目录里最合适。在TaskList列表的右侧有一个判断是否开启的文字标识点击某个列表需要跳转到对应的任务编辑页里。列表组件实现如下
// TaskListComponent.ets
List({ space: Const.LIST_ITEM_SPACE }) {ForEach(this.taskList, (item: ITaskItem) {ListItem() {Row() {Row() {Image(item?.icon)Text(item?.taskName)...}.width(Const.THOUSANDTH_500)Blank().layoutWeight(1)// 状态显示if (item?.isOpen) {Text($r(app.string.already_open))}Image($r(app.media.ic_right_grey)).width(Const.DEFAULT_8).height(Const.DEFAULT_16)}...}...// 路由跳转到任务编辑页.onClick(() {router.pushUrl({url: pages/TaskEditPage,params: {params: formatParams(item)}})})...})
}
TaskListComponent列表组件完整实现如下
// view--/task/--TaskListComponent.ets
import router from ohos.router;
import { CommonConstants as Const } from ../../common/constants/CommonConstants;
import { formatParams } from ../../viewmodel/TaskViewModel;
import { ITaskItem } from ../../model/TaskInitList;Component
export default struct TaskList {Consume taskList: ITaskItem[];build() {List({ space: Const.LIST_ITEM_SPACE }) {ForEach(this.taskList, (item: ITaskItem) {ListItem() {Row() {Row() {Image(item?.icon).width(Const.DEFAULT_24).height(Const.DEFAULT_24).margin({ right: Const.DEFAULT_8 })Text(item?.taskName).fontSize(Const.DEFAULT_20).fontColor($r(app.color.titleColor))}.width(Const.THOUSANDTH_500)Blank().layoutWeight(1)if (item?.isOpen) {Text($r(app.string.already_open)).fontSize(Const.DEFAULT_16).flexGrow(1).align(Alignment.End).margin({ right: Const.DEFAULT_8 }).fontColor($r(app.color.titleColor))}Image($r(app.media.ic_right_grey)).width(Const.DEFAULT_8).height(Const.DEFAULT_16)}.width(Const.THOUSANDTH_1000).justifyContent(FlexAlign.SpaceBetween).padding({ left: Const.DEFAULT_12, right: Const.DEFAULT_12 })}.height(Const.THOUSANDTH_80).borderRadius(Const.DEFAULT_12).onClick(() {router.pushUrl({url: pages/TaskEditPage,params: {params: formatParams(item)}})}).backgroundColor($r(app.color.white))}, (item: ITaskItem) JSON.stringify(item))}.height(Const.THOUSANDTH_1000).width(Const.THOUSANDTH_940)}
}
model数据模型定义
model目录下的数据模型定义
// TaskInitList.ets
import AchievementMapInfo from ../common/bean/AchievementMapInfo;import TaskInfo from ../common/bean/TaskInfo;
import { CommonConstants as Const } from ../common/constants/CommonConstants;export interface ITaskItem {taskID: number;taskName: Resource;isOpen: boolean;unit: string;icon: Resource;dialogBg: Resource;targetValue: string;isAlarm: boolean;startTime: string;endTime: string;frequency: string;isInit: boolean;step: number;
}
ViewModel定义 viewmodel目录下的TaskViewModel定义
import { CommonConstants as Const } from ../common/constants/CommonConstants;
import Logger from ../common/utils/Logger;
import reminder from ../service/ReminderAgent;
import TaskInfoApi from ../common/database/tables/TaskInfoApi;
import { padTo2Digits } from ../common/utils/Utils;
import TaskInfo, { oneWeek } from ../common/bean/TaskInfo;
import { TaskMapById, RemindContentMap, ITaskItem } from ../model/TaskInitList;
import PublishReminderInfo from ../common/bean/PublishReminderInfo;const publishReminder reminder.publishReminder;
const cancelReminder reminder.cancelReminder;
const hasNotificationId reminder.hasNotificationId;
export const taskOriginData: ITaskItem[] TaskMapById;/*** description Get all task status* return object[] Database query results*/
export const getAllTask () {return new PromiseTaskInfo[]((resolve) {TaskInfoApi.query(Const.GLOBAL_KEY, true, (res: TaskInfo[]) {if (res?.length 0) {Logger.warn(queryTaskList, has no data!!);resolve(res ?? []);}resolve(res);})});
}/*** description format data as json string* param params {}*/
export const formatParams (params: ITaskItem) {return JSON.stringify(params);
}
//......
完整的任务列表页
最终的任务列表页面实现如下
// TaskListPage.ets
import { ITaskItem } from ../model/TaskInitList;
import TaskList from ../view/task/TaskListComponent;
import { CommonConstants as Const } from ../common/constants/CommonConstants;
import { getAllTask, taskIndexDataInit, taskOriginData } from ../viewmodel/TaskViewModel;
import TaskInfo from ../common/bean/TaskInfo;Entry
Component
Preview
struct TaskIndex {Provide taskList: ITaskItem[] taskOriginData;onPageShow() {getAllTask().then((res: TaskInfo[]) {let deepCopyDataStr JSON.stringify(this.taskList);let deepCopyData: ITaskItem[] JSON.parse(deepCopyDataStr);this.taskList taskIndexDataInit(deepCopyData, res);})}build() {Row() {Navigation() {Column() {TaskList()}.width(Const.THOUSANDTH_1000).justifyContent(FlexAlign.Center)}.size({ width: Const.THOUSANDTH_1000, height: Const.THOUSANDTH_1000 }).title(Const.ADD_TASK_TITLE).titleMode(NavigationTitleMode.Mini)}.backgroundColor($r(app.color.primaryBgColor)).height(Const.THOUSANDTH_1000)}
}
List组件值的传递
特别注意上述 TaskListPage页面中调用了自定义的TaskList()列表组件如何完成父与子组件的传值的呢即如何把数据从mode中获取出来传递给TaskList组件并未见有参数传递啊。这就涉及arkUI的状态管理相关的装饰器了。
在上述示例中虽然没见到TaskList()列表组件中有参数传递但是发现有 Provide taskList 这一装饰器修饰的变量且把mode中的数据赋值给了它。
在HarmonyOS ArkUI开发框架中Consume和Provide是状态管理相关的装饰器用于组件间的数据传递与同步。它们主要用于跨组件的状态共享尤其是在多层级的父子组件之间。
Provide该装饰器用来声明一个状态变量并将其提供给后代组件使用。当一个状态变量被Provide装饰后这个变量会自动对所有子组件可见无需通过props或事件手动向下级组件传递。后代组件可以直接通过Consume装饰器来获取并使用这个变量。
Consume此装饰器用于从祖先组件中消费获取由Provide提供的状态变量。当在一个组件内使用Consume装饰器时它会绑定到其祖先组件中对应Provide修饰的同名或别名状态变量上实现双向数据同步。
// 在父组件中提供状态
class ParentComponent {Provide(theta)theta_axis 0;// 其他逻辑...
}// 在子组件中消费状态
Entry
Component
struct ChildComponent {Consume(theta) // 使用相同的别名thetaconsumeTheta: number;render() {return Text{Theta Axis Value: ${this.consumeTheta}}/Text;}
}ParentComponent提供了名为“theta”的状态变量而ChildComponent通过Consume装饰器消费了这个变量并在渲染函数中显示它的值。当theta_axis发生变化时ChildComponent中的consumeTheta也会相应更新。
MVVM结构介绍
在HarmonyOS ArkUI开发框架中MVVMModel-View-ViewModel是一种用于构建用户界面的开发模式。它将应用程序分为三个主要部分
Model
Model 代表应用程序的数据模型。在 arkUI 中Model 可能是数据实体、数据访问对象DAO或者远程服务的数据源。Model 负责数据的获取、存储和处理。
View
View视图层 是用户界面的表示。在 arkUI 中View 表示应用程序的界面元素如 UI 控件布局等。View 负责将数据展示给用户并接收用户的交互操作。在ArkUI中视图层由一系列UI组件组成如Text、Image、List等并通过声明式语法进行布局和样式设计。
ViewModel
ViewModel视图模型层作为Model和View之间的桥梁包含了视图所需要的数据以及视图相关的业务逻辑。ViewModel对Model中的数据进行处理并提供给View使用同时响应View的交互事件执行相应的业务操作。在 arkUI 中ViewModel 包含业务逻辑和状态管理负责处理 View 层和 Model 层之间的通信。ViewModel 通常通过数据绑定的方式将数据从 Model 层传递给 View 层并接收来自 View 层的用户输入。
在ArkUI中开发者可以通过数据绑定机制来实现ViewModel和View之间的数据同步即当ViewModel中的数据发生变化时关联的视图会自动更新反之亦然。
通过采用 MVVM 结构arkUI 提供了一种分离关注点、使界面逻辑更易于测试和维护的方式同时也使得界面的设计和逻辑更灵活和可扩展。借助数据绑定开发人员可以更方便地管理界面的数据和状态提高开发效率。通过这样的分离ArkUI的MVVM结构提升了代码可读性、复用性和可测试性同时也简化了用户界面与后端业务逻辑之间的耦合度。
一个典型的mvvm结构
举例一个完整项目典型的mvvm结构。一个好的结构很重要它提升了代码可读性、复用性和可测试性同时也简化了用户界面与后端业务逻辑之间的耦合度。
目录结构示意
├──entry/src/main/ets // 代码区
│ ├──agency // 2x4 ArkTS卡片目录
│ │ └──pages
│ │ └──AgencyCard.ets // 2x4 ArkTS卡片任务
│ ├──common
│ │ ├──constants
│ │ │ └──CommonConstants.ets // 公共常量
│ │ ├──database
│ │ │ ├──rdb // 数据库封装类
│ │ │ │ ├──RdbHelper.ets
│ │ │ │ ├──RdbUtils.ets
│ │ │ │ └──TableHelper.ets
│ │ │ └──tables // 数据表
│ │ │ ├──DayInfoApi.ets
│ │ │ ├──GlobalInfoApi.ets
│ │ └──utils
│ │ ├──BroadCast.ets // 通知
│ │ ├──FormUtils.ets // 卡片操作工具类
│ │ ├──GlobalContext.ets
│ │ ├──Logger.ets // 日志类
│ │ └──Utils.ets // 工具类
│ ├──entryability
│ │ └──EntryAbility.ets // 程序入口类
│ ├──entryformability
│ │ └──EntryFormAbility.ets // 卡片创建更新删除操作类
│ ├──model // model
│ │ ├──AchieveModel.ets
│ │ ├──DatabaseModel.ets // 数据库model
│ │ ├──Mine.ets
│ │ ├──NavItemModel.ets // 菜单栏model
│ │ ├──TaskInitList.ets
│ ├──pages
│ │ ├──MainPage.ets // 应用主页面
│ │ ├──MinePage.ets // 我的页面
│ ├──progress // 2x2 ArkTS卡片目录
│ │ └──pages
│ │ └──ProgressCard.ets // 2x2 ArkTS卡片任务进度
│ ├──service
│ │ └──ReminderAgent.ets // 后台提醒代理操作类
│ ├──view
│ │ ├──dialog // 弹窗组件
│ │ │ ├──AchievementDialog.ets // 成就弹窗
│ │ │ ├──CustomDialogView.ets // 自定义弹窗
│ │ ├──home // 主页面相关组件
│ │ │ ├──AddBtnComponent.ets // 添加任务按钮组件
│ │ │ ├──HomeTopComponent.ets // 首页顶部组件
│ │ │ └──WeekCalendarComponent.ets // 日历组件
│ │ ├──HealthTextComponent.ets // 自定义text组件
│ │ ├──HomeComponent.ets // 首页页面
│ │ ├──ListInfo.ets // 用户信息列表
│ │ └──UserBaseInfo.ets // 用户基本信息
│ └──viewmodel // viewmodel
│ ├──AchievementInfo.ets // 成就信息接口
│ ├──WeekCalendarInfo.ets // 日期信息接口
│ └──WeekCalendarMethodInfo.ets // 日期操作接口
└──entry/src/main/resources // 资源文件目录
其他资源
循环渲染ForEach
HarmonyOS4.0从零开始的开发教程08构建列表页面_harmony 列表界面-CSDN博客
https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/tutorials_List
优秀案例(文档中心)
HarmonyOS 鸿蒙系统 | 鸿蒙学堂