HarmonyOS实战开发-目标管理、如何实现一个自定义弹窗。

介绍

本篇Codelab将介绍如何使用@State、@Prop、@Link、@Watch、@Provide、@Consume管理页面级变量的状态,实现对页面数据的增加、删除、修改。要求完成以下功能:

  1. 实现一个自定义弹窗,完成添加子目标的功能。
  2. 实现一个可编辑列表,可点击指定行展开调节工作目标进度,可多选、全选删除指定行。

相关概念

  • 页面状态管理:用于管理页面级变量的状态。
  • 自定义弹窗: 通过CustomDialogController类显示自定义弹窗。
  • List列表:列表包含一系列相同宽度的列表项。

环境搭建

软件要求

  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:润和RK3568开发板。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。

  1. 完成DevEco Device Tool的安装
  2. 完成RK3568开发板的烧录

3.搭建开发环境。

  1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
  2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
  3. 工程创建完成后,选择使用真机进行调测。

代码结构解读

本篇Codelab只对核心代码进行讲解。

├──entry/src/main/ets                   // ArkTS代码区
│  ├──common
│  │  ├──constants
│  │  │  └──CommonConstants.ets         // 公共常量类
│  │  └──utils
│  │     ├──DateUtil.ets                // 获取格式化日期工具
│  │     └──Logger.ets                  // 日志打印工具类
│  ├──entryability
│  │  └──EntryAbility.ts                // 程序入口类
│  ├──pages
│  │  └──MainPage.ets                   // 主页面
│  ├──view
│  │  ├──TargetInformation.ets          // 整体目标详情自定义组件
│  │  ├──AddTargetDialog.ets            // 自定义弹窗
│  │  ├──ProgressEditPanel.ets          // 进展调节自定义组件
│  │  ├──TargetList.ets                 // 工作目标列表
│  │  └──TargetListItem.ets             // 工作目标列表子项
│  └──viewmodel
│     ├──DataModel.ets                  // 工作目标数据操作类
│     └──TaskItemViewModel.ets          // 任务进展实体类
└──entry/src/main/resources             // 资源文件目录

构建主界面

MainPage作为本应用的主界面,从上至下由三个自定义组件组成。

  1. 标题titleBar。
  2. 目标整体进展详情TargetInformation。
  3. 子目标列表TargetList。

MainPage主要维护五个参数:子目标数组targetData、子目标总数totalTasksNumber、已完成子目标数completedTasksNumber、最近更新时间latestUpdateDate、监听数据变化的参数overAllProgressChanged。具体作用有以下三个方面:

  1. 子组件TargetInformation接收三个参数totalTasksNumber、completedTasksNumber、latestUpdateDate,渲染整体目标详情。
  2. 子组件TargetList接收参数targetData渲染列表。
  3. 使用@Watch监听overAllProgressChanged的变化。当overAllProgressChanged改变时,回调onProgressChanged方法,刷新整体进展TargetInformation。
// MainPage.ets
@Entry
@Component
struct MainPage {// 子目标数组@State targetData: Array<TaskItemViewModel> = DataModel.getData();// 子目标总数@State totalTasksNumber: number = 0;// 已完成子目标数@State completedTasksNumber: number = 0;// 最近更新时间@State latestUpdateDate: string = CommonConstants.DEFAULT_PROGRESS_VALUE;// 监听数据变化的参数@Provide @Watch('onProgressChanged') overAllProgressChanged: boolean = false;	.../*** overAllProgressChanged改变时的回调*/onProgressChanged() {this.totalTasksNumber = this.targetData.length;this.completedTasksNumber = this.targetData.filter((item) => {return item.progressValue === CommonConstants.SLIDER_MAX_VALUE;}).length;this.latestUpdateDate = getCurrentTime();}build() {Column() {// 标题this.titleBar()// 目标整体进展详情TargetInformation({latestUpdateDate: this.latestUpdateDate,totalTasksNumber: this.totalTasksNumber,completedTasksNumber: this.completedTasksNumber})// 子目标列表TargetList({targetData: $targetData,onAddClick: () :void  => this.dialogController.open()})...}...}@BuildertitleBar() {Text($r('app.string.title'))...}
}

添加任务子目标

本章节主要介绍如何实现一个自定义弹窗,完成添加子目标的功能。效果如图所示:

在MainPage.ets中,创建dialogController对象控制弹窗隐显,传入自定义组件AddTargetDialog和点击确定的回调方法saveTask。

// MainPage.ets
@Entry
@Component
struct MainPage {dialogController: CustomDialogController = new CustomDialogController({builder: AddTargetDialog({onClickOk: (value: string): void => this.saveTask(value)}),alignment: DialogAlignment.Bottom,offset: {dx: CommonConstants.DIALOG_OFFSET_X,dy: $r('app.float.dialog_offset_y')},customStyle: true,autoCancel: false});
}

在AddTargetDialog.ets中,参数onClickOk为function类型,接收MainPage传入的saveTask方法。点击确定,调用onClickOk执行saveTask方法,关闭弹窗。

// AddTargetDialog .ets
@CustomDialog
export default struct AddTargetDialog {...private controller?: CustomDialogController;onClickOk?: (value: string) => void;build() {Column() {...Text($r('app.string.add_task_dialog'))...TextInput({ placeholder: $r('app.string.input_target_name')})....onChange((value: string) => {this.subtaskName = value;})Blank()Row() {...Button($r('app.string.confirm_button')).dialogButtonStyle().onClick(() => {if (this.onClickOk !== undefined) {this.onClickOk(this.subtaskName);}})}...}...}
}

在MainPage.ets中,实现saveTask方法:保存数据至DataModel中,并更新targetData的值,完成添加子目标功能。

// MainPage.ets
saveTask(taskName: string) {if (taskName === '') {promptAction.showToast({message: $r('app.string.cannot_input_empty'),duration: CommonConstants.TOAST_TIME,bottom: CommonConstants.TOAST_MARGIN_BOTTOM});return;}DataModel.addData(new TaskItemViewModel(taskName, 0, getCurrentTime()));this.targetData = DataModel.getData();this.overAllProgressChanged = !this.overAllProgressChanged;this.dialogController.close();
}

实现可编辑列表

本章节主要介绍子目标列表TargetList的实现,包括以下功能:

  • 列表项展开。
  • 列表子项点击下拉,滑动滑块更新进展。
  • 列表进入编辑状态,单选、多选、全选、删除子项。

实现列表项展开

实现以下步骤完成点击列表项展开功能:

  1. 使用@State 管理参数isExpanded,表示当前项是否展开,具体表现为自定义组件ProgressEditPanel的显示或隐藏。
  2. 使用@Link和@Watch管理参数clickIndex,表示当前点击ListItem的Index索引。clickIndex值的改变将会传递至所有的ListItem。
  3. 完成onClick点击事件,将isExpanded 值置反,修改clickIndex值为当前点击的索引。
// TargetListItem.ets
@Component
export default struct TargetListItem {@State latestProgress?: number = 0;@Link @Watch('onClickIndexChanged') clickIndex: number;@State isExpanded: boolean = false;...// clickIndex改变的回调方法onClickIndexChanged() {if (this.clickIndex !== this.index) {this.isExpanded = false;}
}build() {...Column() {this.TargetItem()if (this.isExpanded) {Blank()// 自定义组件:编辑面板ProgressEditPanel({slidingProgress: this.latestProgress,onCancel: () => this.isExpanded = false,onClickOK: (progress: number): void => {this.latestProgress = progress;this.updateDate = getCurrentTime();let result = DataModel.updateProgress(this.index, this.latestProgress, this.updateDate);if (result) {this.overAllProgressChanged = !this.overAllProgressChanged;}this.isExpanded = false;},sliderMode: $sliderMode})...}  }....onClick(() => {...if (!this.isEditMode) {animateTo({ duration: CommonConstants.DURATION }, () => {this.isExpanded = !this.isExpanded;})this.clickIndex = this.index;}})}...
}

实现更新进展

列表某项被展开后,实现以下步骤完成更新进展功能:

  1. Slider实现滑动条,滑动滑块调节进展,使用slidingProgress保存滑动值。
  2. 点击确定调用onClickOK方法,将数据slidingProgress回调至TargetListItem。
  3. 在TargetListItem中获取回调的数据并刷新页面。
// ProgressEditPanel.ets
@Component
export default struct ProgressEditPanel {@Link sliderMode: number;@Prop slidingProgress: number = 0;onCancel?: () => void;onClickOK?: (progress: number) => void;build() {Column() {Slider({...})Row() {CustomButton({buttonText: $r('app.string.cancel_button')}).onClick(() => {if (this.onCancel !== undefined) {this.onCancel();}})CustomButton({buttonText: $r('app.string.cancel_button')}).onClick(() => {if (this.onClickOK !== undefined) {this.onClickOK(this.slidingProgress);}})}}}
}

在DataModel.ets中,编写updateProgress方法。该方法根据索引和进度值以及更新日期更新数据。

// DataModel.ets
updateProgress(index: number, updateValue: number, updateDate: string): boolean {if (!this.targetData[index]) {return false;}this.targetData[index].progressValue = updateValue;this.targetData[index].updateDate = updateDate;return true;
}

实现列表多选

列表进入编辑模式才可单选、多选。实现以下步骤完成列表多选功能:

  1. 维护一个boolean类型的数组selectArray,其长度始终与数据列表的长度相等,且初始值均为false。表示进入编辑状态时列表均未选中。
  2. 定义一个boolean类型的值isEditMode,表示是否进入了编辑模式。
  3. TargetListItem选中状态的初始化和点击Checkbox改变TargetListItem的选中状态。
// TargetList.ets
export default struct TargetList {...@State isEditMode: boolean = false;@State selectArray: Array<boolean> = [];...build() {Column() {...if (this.isEditMode) {// 取消按钮Text($r('app.string.cancel_button'))....onClick(() => {this.selectAll = false;this.isEditMode = false;this.selectAllOrCancel(false);})...// 全选按钮Checkbox()....onClick(() => {...this.selectAllOrCancel(this.selectAll);})} else {// 编辑按钮Text($r('app.string.edit_button'))....onClick(() => {this.isEditMode = true;this.selectAllOrCancel(false);})}...}}
}

点击全选Checkbox,将selectArray数组的值全赋值true或false,重新渲染列表为全选或者取消全选状态。

// TargetList.ets
selectAllOrCancel(selectStatus: boolean) {let newSelectArray: Array<boolean> = [];this.targetData.forEach(() => {newSelectArray.push(selectStatus);});this.selectArray = newSelectArray;
}

在TargetListItem中,实现以下步骤改变ListItem的选中状态:

  1. 使用@Link定义selectArr数组接收TargetList传入的selectArray。
  2. 在TargetListItem渲染时,使用this.selectArr[this.index]获取初始选中状态。
  3. 点击Checkbox时,按照当前ListItem的索引,将选中状态保存至selectArr,重新渲染列表完成单选和多选功能。
// TargetListItem.ets
export default struct TargetListItem {...@Link selectArr: Array<boolean>;public index: number = 0;build() {Stack({ alignContent: Alignment.Start }) {...this.TargetItem()...Checkbox()// 获取初始选中状态.select(this.selectArr[this.index])....onChange((isCheck: boolean) => {// 改变被点击项的选中状态this.selectArr[this.index] = isCheck;})......}}
}

实现删除选中列表项

当点击“删除”时,TargetList.ets的deleteSelected方法,实现以下步骤完成列表项删除功能:

  1. 调用DataModel的deleteData方法删除数据。
  2. 更新targetData的数据重新渲染列表。
  3. 修改overAllProgressChanged的值,通知主页刷新整体进展详情TargetInformation。
// TargetList.ets
deleteSelected() {DataModel.deleteData(this.selectArray);this.targetData = DataModel.getData();this.overAllProgressChanged = !this.overAllProgressChanged;this.isEditMode = false;
}

在DataModel.ets中,遍历数据列表,删除被选中的数据项。

// DataModel.ets
export class DataModel {...deleteData(selectArr: Array<boolean>) {if (!selectArr) {Logger.error(TAG, 'Failed to delete data because selectArr is ' + selectArr);}let dataLen = this.targetData.length - CommonConstants.ONE_TASK;for (let i = dataLen; i >= 0; i--) {if (selectArr[i]) {this.targetData.splice(i, CommonConstants.ONE_TASK);}}}getData(): Array<TaskItemViewModel> {return this.targetData;}...
}

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. @State、@Prop、@Link、@Watch、@Provide、@Consume的使用。
  2. List组件的使用。
  3. 自定义弹窗的使用。
  4. Slider组件的使用。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→HarmonyOS教学视频

HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等…视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF

在这里插入图片描述

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. .……

在这里插入图片描述


二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

在这里插入图片描述

三、如何快速入门?《鸿蒙基础入门学习指南》

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. .……

在这里插入图片描述


四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. .……

在这里插入图片描述


五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 7.网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. .……

在这里插入图片描述


更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册

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

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

相关文章

Android14之深入理解sp模板类(二百零二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Android R 广播注册与发送流程分析

静态广播注册时序图 动态广播注册时序图 发送广播时序图 前言 广播接收器可以分为动态和静态&#xff0c;静态广播接收器就是在 AndroidManifest.xml 中注册的&#xff0c;而动态的广播接收器是在代码中通过 Context#registerReceiver() 注册的。 这里先从静态广播的流程开始…

2020年天津市二级分类土地利用数据(矢量)

天津市&#xff0c;位于华北平原海河五大支流汇流处&#xff0c;东临渤海&#xff0c;北依燕山。地势以平原和洼地为主&#xff0c;北部有低山丘陵&#xff0c;海拔由北向南逐渐下降&#xff0c;地貌总轮廓为西北高而东南低。天津有山地、丘陵和平原三种地形&#xff0c;平原约…

深夜变电站三维可视化:电力之心的全新解读

在寂静的深夜&#xff0c;城市的灯火依旧璀璨夺目&#xff0c;而在这背后&#xff0c;有一个不为人知的守护者正在默默工作——那就是变电站。如今&#xff0c;随着科技的飞速发展&#xff0c;我们有了更直观、更生动的方式来了解这个神秘的电力枢纽——三维可视化技术。 深夜变…

前端超分辨率技术应用:图像质量提升与场景实践探索-设计篇

超分辨率&#xff01; 引言 在数字化时代&#xff0c;图像质量对于用户体验的重要性不言而喻。随着显示技术的飞速发展&#xff0c;尤其是移动终端视网膜屏幕的广泛应用&#xff0c;用户对高分辨率、高质量图像的需求日益增长。然而&#xff0c;受限于网络流量、存储空间和图像…

如何在Win10使用IIS服务搭建WebDAV网站并实现无公网IP访问内网文件内容

文章目录 前言1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透&#xff0c;将WebDav服务暴露在公网3.1 安装cpolar内网穿透3.2 配置WebDav公网访问地址 4. 映射本地盘符访问 前言 在Windows上如何搭建WebDav&#xff0c;并且结合cpolar的内网穿透工具实现在公网访…

com.alibaba.boot.nacos.config.binder.NacosBootConfigurationPropertiesBinder解决记录

一直正常的服务突然启动失败了&#xff0c;控制台报错 查询后发现是spring-boot-starter版本2.4和nacos-config 0.2.8版本冲突了 于是看了下nacos-config版本&#xff0c;发现有两个如下 但是原来启动正常&#xff0c;看了下老版本代码发现nacos-config-springboot-autoconfig…

接口自动化测试——文件上传/下载

简介&#xff1a; 轻松搞定文件上传接口和文件下载接口。 我们在做接口自动化测试的时候&#xff0c;经常会碰到文件上传接口和文件下载接口。 那么&#xff0c;文件接口跟普通接口有什么区别呢&#xff1f;又该如何实现呢&#xff1f; 〇、前言 文件上传/下载接口与普通接…

怎么让ChatGPT批量写作原创文章

随着人工智能技术的不断发展&#xff0c;自然语言处理模型在文本生成领域的应用也日益广泛。ChatGPT作为其中的佼佼者之一&#xff0c;凭借其强大的文本生成能力和智能对话特性&#xff0c;为用户提供了一种高效、便捷的批量产出内容的解决方案。以下将就ChatGPT批量写作内容进…

colmap 【Feature matching】特征匹配参数解释

&#xff08;Windows&#xff09;Colmap 具体使用教程可参考我的这篇博文 下面只是matching参数解释 Matching这个阶段很重要&#xff0c;匹配方式不同会对最终结果影响很大&#xff0c;要根据实际情况选择合适的匹配方式。下面是各个参数的详细解释。 1.Exhaustive——官方文…

OSPF---开放式最短路径优先协议

1. OSPF描述 OSPF协议是一种链路状态协议。每个路由器负责发现、维护与邻居的关系&#xff0c;并将已知的邻居列表和链路费用LSU报文描述&#xff0c;通过可靠的泛洪与自治系统AS内的其他路由器周期性交互&#xff0c;学习到整个自治系统的网络拓扑结构;并通过自治系统边界的路…

URL编码:原理、应用与安全性

title: URL编码&#xff1a;原理、应用与安全性 date: 2024/3/29 18:32:42 updated: 2024/3/29 18:32:42 tags: URL编码百分号编码特殊字符处理网络安全应用场景标准演变未来发展 在网络世界中&#xff0c;URL&#xff08;统一资源定位符&#xff09;是我们访问网页、发送请求…

day69实现MyBatis 的Mapper接口 封装SqlSession对象 mapper接口形参怎么给占位符赋值

一 创建项目的准备工作 1 添加jar包 MySql.jar .MyBatis.jar 2 在src中配置MyBatis.xml文件 二 封装SqlSession对象 1 SqlSessionFactoryBuilder 生命周期 这个类可以被实例化,使用和丢弃。一旦你创建了 SqlSessionFactory 后…

九河云荣获“华为2024·亚太区年度杰出合作伙伴奖”

2024年3月26日~27日&#xff0c;以“加速智能化&#xff0c;一切皆服务”为主题的华为亚太生态伙伴大会在东莞隆重开幕&#xff0c;九河云作为专业的多云管理服务商&#xff0c;凭借多年来在云领域的赋能发展应邀出席并荣获“亚太区年度杰出伙伴奖”&#xff0c;这不仅彰显了九…

为什么要学Python?Python的优势在哪?

人生苦短&#xff0c;我用 Python 不知道从什么时候开始流行这句话 Python 是个什么神仙编程语言 为啥全世界都在鼓励孩子学 Python 简单容易上手 国内、国际的竞赛机会多&#xff0c;含金量足 Python 好就业、薪资高 下面且看详细分析 01 什么是Python / 科技编程老师…

MYSQL8.0安装、配置、启动、登入与卸载详细步骤总结

文章目录 一.下载安装包1.方式一.官网下载方式二.网盘下载 二.解压安装三.配置1.添加环境变量 三.验证安装与配置成功四.初始化MYSQL五.注册MySQL服务六.启动与停止MYSQL服务七.修改账户默认密码八.登入MySQL九.卸载MySQL补充&#xff1a;彻底粉碎删除Mysql 一.下载安装包 1.方…

A Little Is Enough: Circumventing Defenses For Distributed Learning

联邦学习的攻击方法&#xff1a;LIE 简单的总结&#xff0c;只是为了能快速想起来这个方法。 无目标攻击 例如总共50个客户端&#xff0c;有24个恶意客户端&#xff0c;那么这个时候&#xff0c;他需要拉拢2个良性客户端 计算 50 − 24 − 2 50 − 24 0.923 \frac{50-24-2}{…

rust使用Command库调用cmd命令或者shell命令,并支持多个参数和指定文件夹目录

想要在不同的平台上运行flutter doctor命令&#xff0c;就需要知道对应的平台是windows还是linux&#xff0c;如果是windows就需要调用cmd命令&#xff0c;如果是linux平台&#xff0c;就需要调用sh命令&#xff0c;所以可以通过cfg!实现不同平台的判断&#xff0c;然后调用不同…

【python】深入探讨flask是如何预防CSRF攻击的

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【C++杂货铺】内管管理

目录 &#x1f308;前言&#x1f308; &#x1f4c1; C/C中内存分布 &#x1f4c1; new 和 delete的使用 &#x1f4c1; new 和 delete的优点 &#x1f4c1; new 和 delete的原理 &#x1f4c2; operator new 和 operator delete函数 &#x1f4c2; 内置类型 &#x1f4c2…