OpenHarmony实战开发-如何实现自定义日历选择器。

567 篇文章 2 订阅
555 篇文章 0 订阅

介绍

本示例介绍通过CustomDialogController类显示自定义日历选择器。

效果图预览 ​

在这里插入图片描述
使用说明

1.加载完成后显示主界面,点当前日期后会弹出日历选择器,选择日期后会关闭弹窗,主页面日期会变成选定的日期,应用退出再进入还是显示上次选择的日期。

实现思路

1.获取当前月和下个月的日期信息。

const SATURDAY = 6 // 日历表上周六对应的序列号,从周日开始算起,取值0~6
export function getMonthDate(specifiedMonth: number, specifiedYear: number) {
  let currentFirstWeekDay: number = 0; // 初始化指定月的第一天是周几
  let currentLastWeekDay: number = 0; // 初始化指定月的最后一天是周几
  let currentAllDay: number[] = []; // 初始化指定月的日期排列数组
  let totalDays = new Date(specifiedYear, specifiedMonth, 0).getDate(); // 初始化指定月总天数
  currentFirstWeekDay = new Date(specifiedYear, specifiedMonth - 1, 1).getDay() // 获取指定月的第一天是周几
  currentLastWeekDay = new Date(specifiedYear, specifiedMonth - 1, totalDays).getDay() // 获取指定月的最后一天是周几
  // 将月份中显示上个月日期的内容置0
  for (let item = 0; item < currentFirstWeekDay; item++) {
    currentAllDay[item] = 0;
  }
  // 将本月日期内容存入数组
  for (let item = 1; item <= totalDays; item++) {
    currentAllDay.push(item);
  }
  // 将月份中显示下个月日期的内容置0
  for (let item = 0; item < SATURDAY - currentLastWeekDay; item++) {
    currentAllDay.push(0);
  }
  return currentAllDay;
}

2.通过CustomDialogController类初始化自定义日历弹窗。

dialogController: CustomDialogController = new CustomDialogController({
  builder: CustomCalendarPickerDialog({
    currentMonth: this.currentMonth,
    currentDay: this.currentDay,
    currentYear: this.currentYear,
    cancel: this.onCancel
  }),
  alignment: DialogAlignment.Bottom, // 自定义弹窗底端对齐
  customStyle: true // 弹窗样式自定义
})

3.设置自定义日历选择器界面。

// 每个月的日期
List({initialIndex: this.initialIndex}) {
  /**
   * 性能知识点:列表中数据较多且不确定的情况下,使用LazyForEach进行数据循环渲染。
   * 当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。
   * 文档参考链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/arkts-rendering-control-lazyforeach-0000001524417213-V2
   */
  LazyForEach(this.contentData, (monthItem: Month) => {
    // 设置ListItemGroup头部组件,显示年份和月份
    ListItemGroup({ header: this.itemHead(monthItem.month) }) {
      ListItem() {
        Grid() {
          // TODO: 高性能知识点: 此处日期固定,使用了ForEach,其他列表数量较多的场景,推荐使用LazyForEach+组件复用+缓存列表项实现
          ForEach(monthItem.days, (day: number) => {
            GridItem() {
              Text(day.toString())
                .fontSize($r('app.string.ohos_id_text_size_headline'))
                .fontColor(day < this.currentDay && monthItem.num ===
                this.currentMonth ? $r('app.color.ohos_id_color_text_secondary') : $r('app.color.ohos_id_color_text_primary'))
            }
            .borderRadius($r('app.string.ohos_id_corner_radius_default_m'))
            .backgroundColor(day === this.dateModel.day && monthItem.num ===
            this.dateModel.month ? $r('app.color.ohos_id_color_palette9') : $r('app.color.ohos_id_color_background'))
            .opacity(day === 0 ? 0 : 1) // 将日期数组中为0的都设置为不显示,即不显示上个月和下个月的内容
            // 点击选定的日期后,关闭日历弹窗,显示日期改变为选择的日期
            .onClick(() => {
              if (day >= this.currentDay || monthItem.num > this.currentMonth) {
                let weekIndex = monthItem.days.indexOf(day) % WEEK_NUMBER; // 将当前日转换成星期显示
                this.dateModel.day = day;
                this.dateModel.week = weekIndex;
                this.dateModel.month = monthItem.num;
                DataManager.setDate(getContext(this), this.dateModel, () => {});
                this.controller.close(); // 关闭自定义弹窗
              }
            })
          })
        }
        .backgroundColor($r('app.color.ohos_id_color_background'))
        .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
        // 当前月显示的数组元素个数大于35则显示6行,否则显示5行
        .rowsTemplate(monthItem.days.length > MONTH_NUMBER ? '1fr 1fr 1fr 1fr 1fr 1fr' : '1fr 1fr 1fr 1fr 1fr')
        .height(monthItem.days.length > MONTH_NUMBER ? GRID_HEIGHT_L : GRID_HEIGHT_M)
      }
    }
  })
}

4.通过用户首选项实现选择的日期数据持久化。

static setDate(context: Context, dateModel: DateModel, callback: () => void) {
  try {
    // 获取Preferences实例
    let promise = dataPreferences.getPreferences(context, 'date')
    promise.then((object: dataPreferences.Preferences) => {
      try {
        // 将数据写入缓存的Preferences实例中
        let setPromise = object.put('selectedDate', JSON.stringify(dateModel))
        setPromise.then(() => {
          // 将缓存的Preferences实例中的数据异步存储到用户首选项的持久化文件中
          let flushPromise = object.flush()
          flushPromise.then(() => {
            // 创建单个AppStorage的键值对
            AppStorage.setOrCreate<DateModel>('selectedDate', dateModel)
            callback()
          }).catch((err: Error) => {
            callback()
            console.error("LoginMessage: Failed to flush" + err.name + ", message = " + err.message)
          })
        }).catch((err: Error) => {
          callback()
          console.error("LoginMessage: Failed to put selectedDate" + err.name + ", message = " + err.message)
        })
      } catch (err) {
        callback()
        console.error("LoginMessage: Failed to put selectedDate" + err.name + ", message = " + err.message)
      }
    }).catch((err: Error) => {
      callback()
      console.error("LoginMessage: Failed to get preferences" + err.name + ", message = " + err.message)
    })
  } catch (err) {
    callback()
    console.error("LoginMessage: Failed to get preferences" + err.name + ", message = " + err.message)
  }
}

高性能知识点

本示例使用了LazyForEach进行数据懒加载,List布局时会根据可视区域按需创建ListItem组件,并在ListItem滑出可视区域外时销毁以降低内存占用。 LazyForEach:数据懒加载

工程结构&模块类型

customcalendarpickerdialog                      // har类型
|---components
|   |---DataManager.ets                         // 持久化方法
|   |---DateModel.ets                           // 数据类型定义
|   |---GetDate.ets                             // 获取日期信息
|   |---MonthDataSource.ets                     // 数据类型定义
|---view
|   |---CustomCalendarPickerDialog.ets          // 视图层-自定义日历
|   |---CalendarView.ets                        // 视图层-场景主页面

模块依赖

本实例依赖common模块来实现资源的调用。

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

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

在这里插入图片描述
在这里插入图片描述

鸿蒙生态应用开发白皮书V2.0PDF: 获取完整版白皮书方式请点击→https://docs.qq.com/doc/DZVVkRGRUd3pHSnFG?u=a42c4946d1514235863bb82a7b2ac128

在这里插入图片描述

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

一、入门必看→https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.应用开发导读(ArkTS)
2………
在这里插入图片描述

二、HarmonyOS 概念→https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.系统定义
2.技术架构
3.技术特性
4.系统安全
5.…在这里插入图片描述

三、如何快速入门?→https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.基本概念
2.构建第一个ArkTS应用
3………在这里插入图片描述

四、开发基础知识→https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

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

五、基于ArkTS 开发→https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

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

更多了解更多鸿蒙开发的相关知识可以参考:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值