HarmonyOS开发实战( Beta5.0)日历切换案例实践详解

news2024/11/24 17:20:42

鸿蒙HarmonyOS开发往期必看:

HarmonyOS NEXT应用开发性能实践总结

最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)


介绍

本示例介绍使用Swiper实现自定义日历月视图和周视图左右滑动切换月或周的效果。同时使用分段按钮和Tabs实现月视图和周视图的切换效果。

效果图预览

使用说明

  1. 进入页面,在月视图上手指往右滑动,可切换到上个月,往左滑动可切换到下个月。

  2. 在月视图上点击非当日日期,日期上显示绿色边框选中效果。选中当日日期,当日日期显示为红底白字。

  3. 月视图上点击非当月的日期,可切换到对应月,同时日期显示选中效果。

  4. 点击“周”按钮,可从月视图切换到周视图,周视图展示的周信息根据月视图之前选中的日期进行跳转。

  5. 周视图左右滑动可切换下一周和上一周。

  6. 周视图上选中日期后,点击“月”按钮,可从周视图切换到月视图,月视图展示的月份信息根据周视图之前选中的日期进行月份跳转。

  7. 周视图切换时,默认根据周视图中第一天的年月信息刷新页面顶部的“xxxx年x月”数据。手动点击周视图日期时,则根据选中的年月信息刷新数据。

实现思路

  1. 自定义日历组件CustomCalendar。这里参考日历三方库@xsqd/calendar的部分源码使用两个ForEach循环实现日历的月视图和周视图的日期布局效果。通过CalendarStateType条件渲染对应的月视图或周视图。源码参考CustomCalendar.ets。
if (this.calendarState === CalendarStateType.MONTH) {
  // 月视图
  ForEach(this.monthDays, (items: Day[], index: number) => {
    Row() {
      ForEach(items, (item: Day) => {
        this.monthDayBuilder(item, index + 1)
      }, (item: Day, index: number) => {
        return item.dayNum + "" + index
      })
    }
    .width($r('app.string.calendar_switch_full_size'))
    .justifyContent(FlexAlign.SpaceBetween)
  }, (item: Day[], index: number) => {
    return item.reduce((item1, item2) => {
      return item1 + item2.dayInfo.year + item2.dayInfo.month + item2.dayInfo.date
    }, '') + index
  })
} else if (this.calendarState === CalendarStateType.WEEK) {
  // 周视图
  ForEach(this.weekDays, (items: Day[], index: number) => {
    Row() {
      ForEach(items, (item: Day) => {
        this.weekDayBuilder(item)
      }, (item: Day, index: number) => {
        return item.dayNum + "" + index;
      })
    }
    .width($r('app.string.calendar_switch_full_size'))
    .justifyContent(FlexAlign.SpaceBetween)
  }, (item: Day[], index: number) => {
    return item.reduce((item1, item2) => {
      return item1 + item2.dayInfo.year + item2.dayInfo.month + item2.dayInfo.date
    }, '') + index
  })
}
  1. 为了实现月视图和周视图的左右切换月或周的效果,通过在Swiper里分别使用三个自定义日历组件CustomCalendar实现。以月视图为例,Swiper中索引0,1,2分别对应上个月,本月,下个月份的数据,通过yearMonthInfo进行指定。周视图类似,通过weekNum指定上一周,本周,下一周的数据。源码参考CalendarSwitch.ets。
Swiper() {
  CustomCalendar({
    currentSelectDay: this.currentSelectDay, // 必选项。选中的日期(年月日)
    yearMonthInfo: this.lastYearMonth, // 必选项。设置日历年月信息
    weekNum: this.weekNumDefault, // 必选项。仅用于周视图,weekNum需要使用@Link。月视图没有实际作用。
    onCalendarClick: (item: CalendarData) => {
      // 可选项。日期点击监听
      hilog.info(0x0000, TAG, `day: ${JSON.stringify(item)}`);
    },
    CalendarStyle: {
      textScaling: TEXT_SCALE, // 可选项。公历,农历文字缩放比例
    },
    ColorType: {
      backgroundColor: Color.Transparent, // 可选项。日历背景色
      monthDayColor: Color.Black, // 可选项。本月公历日期颜色
      noMonthDayColor: Color.Gray, // 可选项。非本月公历日期颜色
      lunarColor: Color.Gray // 可选项。农历的文字颜色
    }
  })

  CustomCalendar({
    currentSelectDay: this.currentSelectDay,
    yearMonthInfo: this.currentYearMonth,
    weekNum: this.weekNumDefault,
    onCalendarClick: (item: CalendarData) => {
      hilog.info(0x0000, TAG, `day: ${JSON.stringify(item)}`);
    },
    CalendarStyle: {
      textScaling: TEXT_SCALE,
    },
    ColorType: {
      backgroundColor: Color.Transparent,
      monthDayColor: Color.Black,
      noMonthDayColor: Color.Gray,
      lunarColor: Color.Gray
    }
  })

  CustomCalendar({
    currentSelectDay: this.currentSelectDay,
    yearMonthInfo: this.nextYearMonth,
    weekNum: this.weekNumDefault,
    onCalendarClick: (item: CalendarData) => {
      hilog.info(0x0000, TAG, `day: ${JSON.stringify(item)}`);
    },
    CalendarStyle: {
      textScaling: TEXT_SCALE,
    },
    ColorType: {
      backgroundColor: Color.Transparent,
      monthDayColor: Color.Black,
      noMonthDayColor: Color.Gray,
      lunarColor: Color.Gray
    }
  })
}
  1. 月视图和周视图都是根据Swiper的onChange事件(当前显示的子组件索引变化)进行月份或周的切换。以月视图为例,通过oldMonthViewIndex存储上一次的Swiper索引值,然后跟本次切换的索引进行比较,来识别月份是左滑还是右滑。然后根据当前切换后的索引值去刷新所需的月份。例如,假设swiper索引0(7月),swiper索引1(8月),swiper索引2(9月),当前Swiper显示的索引为1。当Swiper右滑从索引1(8月)切换到索引0(7月)时,需要把Swiper里索引2(9月)的月份更新为6月的数据。周视图的onChange也是类似处理逻辑,这里不再赘述。源码参考CalendarSwitch.ets。
.onChange((index: number) => {
  if (this.oldMonthViewIndex === index) {
    return;
  }
  // 判断是否右滑切换月份
  const IS_RIGHT_SLIDE: boolean =
    (this.oldMonthViewIndex === 1 && index === 0) || (this.oldMonthViewIndex === 0 && index === 2) ||
      (this.oldMonthViewIndex === 2 && index === 1);
  this.oldMonthViewIndex = index;
  // 右滑切换月份
  if (IS_RIGHT_SLIDE) {
    if (index === 0) {
      // swiper索引右滑到0时,修改swiper索引2的月份为当前月份(索引0)的上一个月。比如,假设swiper索引0(7月),swiper索引1(8月),swiper索引2(9月)。当左滑切换到索引0(7月)时,需要把索引2(9月)的月份改成6月。
      this.setMonthViewLeftSlide();
      // 修改swiper索引2的月份为当前月份(索引0)的上一个月
      this.nextYearMonth.year = this.getLastYear();
      this.nextYearMonth.month = this.getLastMonth();
    } else if (index === 1) {
      // swiper索引右滑到1时,修改swiper索引0的月份为当前月份(索引1)的上一个月。
      this.setMonthViewLeftSlide();
      this.lastYearMonth.year = this.getLastYear();
      this.lastYearMonth.month = this.getLastMonth();
    } else if (index === 2) {
      // swiper索引右滑到2时,修改swiper索引1的月份为当前月份(索引2)的上一个月。
      this.setMonthViewLeftSlide();
      this.currentYearMonth.year = this.getLastYear();
      this.currentYearMonth.month = this.getLastMonth();
    }
  } else {
    // 左滑切换月份
    if (index === 0) {
      // swiper索引左滑到0时,修改swiper索引1的月份为当前月份(索引0)的下一个月。
      this.setMonthViewRightSlide();
      this.currentYearMonth.year = this.getNextYear();
      this.currentYearMonth.month = this.getNextMonth();
    } else if (index === 1) {
      // swiper索引左滑到1时,修改swiper索引2的月份为当前月份(索引1)的下一个月。
      this.setMonthViewRightSlide();
      this.nextYearMonth.year = this.getNextYear();
      this.nextYearMonth.month = this.getNextMonth();
    } else if (index === 2) {
      // swiper索引左滑到2时,修改swiper索引0的月份为当前月份(索引2)的下一个月。
      this.setMonthViewRightSlide();
      this.lastYearMonth.year = this.getNextYear();
      this.lastYearMonth.month = this.getNextMonth();
    }
  }
})
  1. 月视图和周视图之间的切换通过changeIndex控制Tabs切换到指定月视图或周视图的页签。从周视图切换到月视图时,月视图需要刷新的月份数据根据目前选中的日期currentSelectDay中的年月信息设置CustomCalendar的yearMonthInfo,然后通过触发yearMonthInfo的updateMonthViewData监听进行月份数据刷新(getMonthViewData)。从月视图切换到周视图时,周视图需要刷新的周数据,也是根据目前选中的日期currentSelectDay中的年月日信息。通过计算选中日期到今天相差几周,来计算需要传入CustomCalendar的weekNum,触发updateWeekData监听,进行周数据刷新(getWeekViewData)。源码参考CalendarSwitch.ets。
if (this.tabSelectedIndexes[0] === 0) {
  // 切到月视图
  this.tabController.changeIndex(0);
  // 月视图swiper索引重置为1
  this.swiperMonthIndex = 1;
  this.oldMonthViewIndex = 1;
  // 刷新年月数据
  this.currentShowYear = this.currentSelectDay.year;
  this.currentShowMonth = this.currentSelectDay.month;
  this.currentYearMonth.year = this.currentSelectDay.year;
  // month设置-1是为了在周视图选择过日期后,切换回月视图时触发月视图的刷新
  this.currentYearMonth.month = -1;
  this.currentYearMonth.month = this.currentSelectDay.month;
  this.lastYearMonth.year =
    (this.currentYearMonth.month - 1 < 1) ? this.currentYearMonth.year - 1 : this.currentYearMonth.year;
  this.lastYearMonth.month = (this.currentYearMonth.month - 1 < 1) ? 12 : this.currentYearMonth.month - 1;
  this.nextYearMonth.year =
    (this.currentYearMonth.month + 1 > 12) ? this.currentYearMonth.year + 1 : this.currentYearMonth.year;
  this.nextYearMonth.month = (this.currentYearMonth.month + 1 > 12) ? 1 : this.currentYearMonth.month + 1;
} else if (this.tabSelectedIndexes[0] === 1) {
  // 切到周视图
  this.tabController.changeIndex(1);
  // 周视图swiper索引重置为1
  this.swiperWeekIndex = 1;
  const SELECT_DAY =
    new Date(this.currentSelectDay.year, this.currentSelectDay.month - 1, this.currentSelectDay.date);
  // 计算目前选中的日期selectDay距离今天相差的周数
  const WEEKS_BETWEEN = this.weeksBetweenDates(SELECT_DAY);
  this.weekNumOne = WEEKS_BETWEEN - 1; // 设置上一周
  this.weekNumTwo = WEEKS_BETWEEN; // 设置本周
  this.weekNumThree = WEEKS_BETWEEN + 1; // 设置下一周
}

高性能知识点

本示例中月视图左右滑动切换日历月份时,只更新一个月数据。周视图每次切换周时,只更新一周的数据,以优化日历左右切换时的性能。

以下是使用DevEco Studio内置的Profiler中的帧率分析工具Frame抓取本案例性能的相关数据(性能耗时数据因设备版本而异,以实测为准):

  1. 响应时延。在cases工程案例列表中找到本案例模块,使用Frame抓取从点击案例模块到跳转进入案例页面绘制第一帧的耗时。如下图所示,可以看出点击响应时延为13.1ms。

  1. 完成时延。在cases工程案例列表中找到本案例模块,使用Frame抓取从点击案例模块到跳转案例页面的转场动画结束的耗时,如下图所示,可以看出完成时延为791.9ms。

  1. 月视图左右滑动切换月份的帧率,如下图所示,可以看出月视图左右滑动切换月份的帧率为118.0fps。通过RenderFrame(执行GPU绘制)标签可以看出,滑动切换月份过程的平均渲染耗时为3.969ms。

  1. 周视图左右滑动切换周的帧率,如下图所示,可以看出周视图左右滑动切换周的帧率为119.9fps。通过RenderFrame(执行GPU绘制)标签可以看出,滑动切换周过程的平均渲染耗时为4.107ms。

工程结构&模块类型

calendarswitch                               // har类型
|---constant
|   |---Constants.ets                        // 常量定义
|---model
|   |---CalendarModel.ets                    // 日历配置
|---utils
|   |---TimeUtils.ets                        // 日历工具类
|---view
|   |---CalendarSwitch.ets                   // 日历切换页面
|   |---CustomCalendar.ets                   // 自定义日历组件

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为体系杂乱无章,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线、视频、文档用来跟着学习是非常有必要的。

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员

鸿蒙 NEXT 全栈开发学习笔记 希望这一份鸿蒙学习文档能够给大家带来帮助~


 鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频教程+学习PDF文档

(鸿蒙语法ArkTS、TypeScript、ArkUI教程……)

 纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

                   

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

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

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

相关文章

反编译app

反编译代码步骤&#xff1a; 1.用dex2jar 将apk打成jar&#xff0c;d2j-dex2jar your-app.apk GitHub - pxb1988/dex2jar: Tools to work with android .dex and java .class filesTools to work with android .dex and java .class files - pxb1988/dex2jarhttps://github.co…

注解实现json序列化的时候自动进行数据脱敏

最近在进行开发的时候遇到一个问题&#xff0c;需要对用户信息进行脱敏处理&#xff0c;原有的方式是写一个util类&#xff0c;在需要脱敏的字段查出数据后&#xff0c;显示掉用方法处理后再set回去&#xff0c;觉得这种方式能实现功能&#xff0c;但是不是特别优雅&#xff0c…

机器学习特征分析

机器学习的常规流程 在真正进入机器学习算法之前&#xff0c;数据准备和处理过程会尤为重要&#xff0c;这直接关系到后续模型的效果和最终的业务判决。 数据分析 什么是数据分析 数据分析指对原始数据进行检查、清理、转换及筛选等一系列动作&#xff0c;找到数据对结果的影…

Qwen1.5模型文本分类微调实战教程

大家好啊!今天咱们来聊聊怎么给大语言模型"调教"一下&#xff0c;让它在文本分类这个任务上玩得更溜。具体来说&#xff0c;我们要用Qwen1.5这个模型来做文章。别看这活儿听着高大上&#xff0c;其实做起来也没那么难。跟着我来&#xff0c;保证让你轻松上手! 咱们这…

How to fool AI content detectors?

Add prompt below: Make it sound like a tweed jacket wearing professor taking to a group of 20 years old students. Vary the sentences length. Make it persoanl, add a touch of humor. Make the blog post sound unique when compared to Other blog posts.

MySQL--库的操作

文章目录 1.创建数据库2.创建数据库案例3.字符集和校验规则3.1默认字符集3.2默认校验规则3.3查看系统默认字符集以及校验规则3.4查看数据库支持的字符3.5查看数据库支持的字符集校验规则3.6校验规则对数据库的影响不区分大小写查询&#xff1a;排序结果&#xff1a;区分大小写查…

BFS广度优先搜索和DFS深度优先搜索解决迷宫问题

前言 BFS广度优先搜索和DFS深度优先搜索解决迷宫问题 迷宫问题 原题目&#xff1a;迷宫由n行m列的单元格组成(n,m都小于等于50)&#xff0c;每个单元格要吗是空地要吗是障碍物。现在请你找到一条从起点到终点的最短路径长度。 分析 BFS广度优先搜索 首先我们将起点入队&a…

iOS 18 RC 版本更新,为相机应用引入了“暂停录制视频”功能

苹果公司9月10日正式向全球iPhone用户推送了iOS 18 Release Candidate&#xff08;RC&#xff09;版本。这一版本的发布不仅标志着iOS系统的又一次重大更新&#xff0c;更预示着苹果在提升用户体验、增强隐私保护以及推动AI应用方面的持续努力。 并且此次苹果公司最新推出的 i…

Unity基本操作

API手册 Unity 脚本 APIhttps://docs.unity.cn/cn/2022.3/ScriptReference/index.html 在遇到不懂的方法、想更深入的学习或者是想查看是否有相应的方法实现某项功能&#xff0c;可以在Unity官方这里查看脚本。以Transform为例&#xff0c;可以直接搜索&#xff0c;或者在Unit…

9月12日 QT

//设置图片缩放适应label ui->label->setScaledContents(true); // 在spinbox后方设置$特殊符号 ui->spinBox->setSuffix(" 斤"); //给肉类combobox加入项目 QStringList Meat_List{"请选择&quo…

数据放到GPU上,运行程序卡住检查方法

这个问题一定是要结合具体的代码&#xff0c;下面就自己遇到问题&#xff0c;询问chatGPT后发现问题所在的过程进行记录&#xff0c;当然绝大部分情况下都是batch_size设置太大了&#xff0c;显卡内存不足导致 部分重点代码&#xff1a; 导入模型部分略 #自定义数据集有关类 c…

无人机 PX4 飞控 | EKF2简介与使用方法

无人机 PX4 飞控 | EKF2简介与使用方法 PX4 EKF2简介EKF 的启动ecl EKF 的优缺点缺点优点 运行单个EKF实例运行多个EKF实例 PX4 EKF2简介 PX4是一个流行的开源飞控系统&#xff0c;广泛用于无人机和其他自动驾驶飞行器。EKF2&#xff08;Extended Kalman Filter 2&#xff09;…

IEEE 802.11a OFDM系统的仿真(续)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第九章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; clear all %%%%%%%参数设计部分%%%%%%%Nsp52;%系统子载波数&#xff08;不包括直流载波&#xff09; Nfft64;%FFT长度 Ncp16;…

ppt文档怎么转换成pdf?快来试试这几种转换方法!

ppt文档怎么转换成pdf&#xff1f;在日常工作与学习的广阔舞台上&#xff0c;PPT&#xff0c;这一演示文稿的常青树&#xff0c;无疑是表达创意、传递信息的重要工具&#xff0c;然而&#xff0c;正如每枚硬币都有其两面&#xff0c;PPT在带来便捷的同时&#xff0c;也显露出一…

js | TypeError: Cannot read properties of null (reading ‘indexOf’) 【解决】

js | TypeError: Cannot read properties of null (reading ‘indexOf’) 【解决】 描述 概述 在前端开发中&#xff0c;遇到TypeError: Cannot read properties of null (reading indexOf)这类错误并不罕见。这个错误通常表明你试图在一个null值上调用indexOf方法&#xff0c…

Linux基础---05输入输出重定向

一.输出重定向符号> 操作1 > 文件 &#xff1a;将操作1的结果覆盖到文件里&#xff0c;并且此文件之前的数据全部清空。 操作2 >>文件&#xff1a;将操作2的结果追加到文件里&#xff0c;原文件的内容不会被清空。 操作3 1>right.txt 2>wrong.txt:操作3的返…

C 盘突然爆满,罪魁祸首竟然是 ...... !

今天打开电脑的时候突然发现 C 盘进度条变红了&#xff0c;这很不正常&#xff01; 做软件开发的应该都会经常在各种磁盘中查找文件和资料&#xff0c;也就会频繁打开 此电脑 窗口&#xff0c;因此即使不是刻意去观察各个磁盘的容量&#xff0c;也会时不时瞟一眼每个盘的占用条…

Java特殊文件xml—利用Dom4J解析xml文件(完整详解,附有代码+案例)

文章目录 三十.特殊文件30.1 xml概述30.1 xml文件30.2 Dom4J解析xml30.2.1 案列130.2.2 案例2 三十.特殊文件 30.1 xml概述 可扩展标记语言 可扩展&#xff1a;标签名字可以自己定义 优点&#xff1a;易于阅读&#xff0c;可以配置成组出现的数据 缺点&#xff1a;解析比较复…

对称矩阵的压缩存储

1.给自己出题&#xff1a;自己动手创造&#xff0c;画一个5行5列的对称矩阵 2.画图&#xff1a;按“行优先”压缩存储上述矩阵&#xff0c;画出一维数组的样子 3.简答&#xff1a;写出元素 i,j 与 数组下标之间的对应关系 4.画图&#xff1a;按“列优先”压缩存储上述矩阵&a…

盐湖卤水中提取铷、铯

盐湖卤水中提取铷、铯是一个复杂但具有重要意义的过程&#xff0c;因为铷、铯是稀有的金属元素&#xff0c;在高科技、航空航天、新能源等领域有广泛应用。以下是从盐湖卤水中提取铷、铯的详细分析&#xff1a;我国盐湖资源丰富&#xff0c;盐类资源总量约12000亿吨&#xff0c…