OpenHarmony - 基于ArkUI框架实现日历应用

系统 OpenHarmony
eTS语言:基于TypeScript(简称TS)拓展的出来的,是OpenHarmony应用开发语言,使用ArkUI框架提供的组件进行界面开发。

想了解更多关于开源的内容,请访问:

51CTO 鸿蒙开发者社区

https://ost.51cto.com

前言

对于刚刚接触OpenHarmony应用开发的开发者,最快的入门方式就是开发一个简单的应用,下面记录了一个日历应用的开发过程,通过日历应用的开发,来熟悉基本图形的绘制,ArkUI的组件的使用,UI组件生命周期,加深对OpenHarmony应用开发的理解。

效果展示

开发环境

  • 开发工具:DevEco Studio 3.1 Release
  • 开发环境:OpenHarmony API 9
  • 开发语言:eTS

关于eTS

eTS语言:基于TypeScript(简称TS)拓展的出来的,是OpenHarmony应用开发语言,使用ArkUI框架提供的组件进行界面开发。

什么是TypeScript:
TypeScript 是微软开发的一个开源的编程语言,是面向对象强类型化的,在 JavaScript 的基础上引入了静态类型、类、接口的概念。

TypeScript 和 JavaScript 的区别:

  • TypeScript 是 JavaScript 的超集,在JavaScript的基础上拓展了语法,包含了 JavaScript 的所有元素
  • 在TypeScript 中的数据要求有明确的类型,而JavaScript中没有
  • TypeScript在编译时可以发现错误,JavaScript只有在运行时报错

布局容器组件

  • Column :沿垂直方向布局的容器,可以包含多个子组件
  • Row:沿水平方向布局容器,可以包含多个子组件
  • Stack:堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件,可以包含多个子组件
  • Flex:弹性布局,元素在容器内水平居中,垂直等间隔分散,可以包含多个子组件
  • Scroll:可滑动的容器组件,当子组件的布局尺寸超过父组件的视口时,内容可以滑动,内部只支持单个子组件,可支持垂直或者水平滑动
  • Tabs:一种可以通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图,只能包含子组件TabContent
  • List:列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本,只能包含ListItem子组件
  • Swiper:滑动容器,提供左右切换子组件显示的能力,可以包含多个子组件
  • Grid:网格容器,由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局,只能包含GridItem子组件

绘制组件

  • Circle:圆形绘制组件
  • Ellipse:椭圆绘制组件
  • Line:直线绘制组件
  • Polyline:折线绘制组件
  • Polygon:多边形绘制组件
  • Path:路径绘制组件
  • Rect:矩形绘制组件
  • Shape:绘制组件的父组件,父组件中会描述所有绘制组件均支持的通用属性。

自定义组件

自定义组件生命周期函数

  • aboutToAppear:在组件的 build 函数之前执行,可以做数据的初始化操作。
  • aboutToDisappear:在组件销毁之前执行,不允许改变状态变量,会导致应用程序行为不稳定,可以做资源的释放操作。
  • onPageShow:仅@Entry修饰的自定义组件生效,应用进入前台台,页面显示时触发。
  • onPageHide:仅@Entry修饰的自定义组件生效,应用进入后台,页面消失时触发。

自定义组件常用属性

  • @State :变量需要本地初始化,初始化的值可以被构造参数覆盖;
  • @Prop:必须通过构造函数参数初始化,属于单向数据绑定,使用其父组件提供的@State变量进行初始化
  • @Link:必须通过构造函数参数进行初始化,属于双向数据绑定,子组件对@Link变量的更改将同步修改父组件的@State变量;

实现过程

日历一页显示42天,包括上个月、当前月、下个月的天数,上个月和下个月的日期显示灰色,点击日期显示选中效果。
支持选择年份、月份,指定一个日期,获取当前月的天数,根据该月1号在一周中的第几天,获取上个月显示的天数,以及下个月显示的天数。

获取上一个月的天数,根据指定月份的1号在一周的第几天,上月最大天数,计算出上个月天数,以object的形式添加到数组,以便区分,代码如下:

const prevMonthDays = [];
//获取上个月最大天数
let prevLastDay = new Date(year, month-1, 0).getDate();
//获取某月1号所在一周的第几天
let startWeek = new Date(year, month, 1).getDay();
// 上个月的最大天数减去当前月1号所在一周的第几天
for (let i = prevLastDay - startWeek + 1; i <= prevLastDay; i++) {
      prevMonthDays.push({
        date: new Date(year, month - 1, i),
        status: 'prev'
      });
}

获取下一个月的天数,根据当前月份的1号在一周的第几天,当前月份的最大天数,计算出下个月天数,以object的形式添加到数组,以便区分,代码如下:

const nextMonthDays = [];
//获取下个月最大天数
let curLastDay = new Date(year, month, 0).getDate();
//获取当前月份1号在一周的第几天
let startWeek = new Date(year, month, 1).getDay();
//一页的天数减去当前月份的天数和上个月的天数
for (let i = 1; i <= 42 - startWeek - curLastDay + 1; i++) {
      nextMonthDays.push({
        date: new Date(year, month + 1, i),
        status: 'next'
      });
}

获取当前月的天数,以object的形式添加到数组,以便区分,代码如下:

let curLastDay = new Date(year, month, 0).getDate();
for (let i = 1; i <= curLastDay; i++) {
      curMonthDays.push({
        date: new Date(year, month, i),
		
        status: 'current'
      });
}

屏幕适配

屏幕适配需要用到媒体查询的接口,可以根据设备参数,例如:屏幕分辨率、横竖屏切换来修改应用的样式。

首先导入媒体查询模块:

import mediaquery from '@ohos.mediaquery'

然后通过matchMediaSync接口设置媒体查询条件,并保存返回的条件监听句柄,例如:监听设备类型,横竖屏状态。

//监听横竖屏状态
private listener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(orientation: landscape)');
//监听当前设备类型
private deviceListener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('screen and (device-type: default)');

定义触发回调函数,当匹配到媒体查询条件时会触发此回调函数。

onOrientationChange = (mediaQueryResult) => {
  if (mediaQueryResult.matches) {
    this.calendarWidth = "70%"
    this.titleBarLeft = 80
  } else {
    this.calendarWidth = "100%"
    this.titleBarLeft = 20
  }
}
onDeviceTypeChange = (mediaQueryResult) => {
  if(mediaQueryResult.matches){
    this.titleBarLeftTop = 10
    this.weekHeight = 30
    this.pikerDialogHeight = 200
    console.log("onDeviceTypeChange  device-type: default")
  }else{
    this.titleBarLeftTop = 40
    this.weekHeight = 50
    this.pikerDialogHeight = 280
  }
}

通过条件监听句柄去注册回调函数,在 aboutToAppear 组件初始化的时候执行注册,退出时销毁监听。

//组件初始化
aboutToAppear() {
  this.listener.on('change', this.onOrientationChange);
}
//组件销毁
aboutToDisappear(){
  this.listener.off('change', this.onOrientationChange);
}

数据懒加载

当列表加载的数据过大时,直接采用循环渲染方式,导致页面启动时间过长,可以使用LazyForEach组件进行数据的懒加载进行优化,按需加载数据并创建相应组件。

定义一个类并实现IDataSource接口:

export class YearData implements IDataSource{

  private list: number[] = []
  private listener: DataChangeListener

  constructor(list: number[]) {
    this.list = list
  }

  totalCount(): number {
    return this.list.length
  }

  getData(index: number): any {
    return this.list[index]
  }

  getDataIndex(data:any){
    return this.list.indexOf(data)
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    this.listener = listener
  }

  unregisterDataChangeListener() {
  }
}

在页面中导入并使用。

import { YearData } from '../datasource/YearData'

private data: YearData = new YearData([])
LazyForEach(this.data, (item: string) => {
        ListItem() {
          Row() {
            Text(item).fontSize(20).margin({ left: 10 })
          }
        }
        .onClick(() => {
          this.data.pushData('item value: ' + this.data.totalCount())
        })
      }, item => item)
}

总结

日历应用实现在一页42个格子上显示上个月、当前月、下个月的日期,通过日历应用的开发了解到了ArkUI组件的一些用法,生命周期和数据的加载过程,对之后的应用开发有很大的帮助。

想了解更多关于开源的内容,请访问:

51CTO 鸿蒙开发者社区

https://ost.51cto.com

责任编辑:jianghua 来源: 51CTO 鸿蒙开发者社区
相关推荐

2022-07-26 14:40:42

ArkUIJS

2022-05-27 14:55:34

canvas画布鸿蒙

2022-08-04 13:55:08

拼数字小游戏鸿蒙

2022-09-15 15:04:16

ArkUI鸿蒙

2022-09-20 14:35:59

ArkUI鸿蒙JS

2023-08-17 15:04:22

2022-10-24 14:49:54

ArkUI心电图组件

2022-11-02 16:06:54

ArkUIETS

2022-08-05 19:37:59

鸿蒙Api框架

2021-12-27 15:10:55

鸿蒙HarmonyOS应用

2022-03-17 15:28:18

五子棋HarmonyOSJSAPI

2022-09-16 15:34:32

CanvasArkUI

2022-08-05 19:27:22

通用API鸿蒙

2022-10-17 14:36:09

ArkUI虚拟摇杆组件

2022-09-14 15:17:26

ArkUI鸿蒙

2022-06-28 14:42:26

ETS购物车应用

2022-07-13 16:24:12

ArkUI(JS)打地鼠游戏

2022-09-21 14:51:21

ArkUI信件弹出

2021-12-01 15:40:23

鸿蒙HarmonyOS应用

2023-08-17 15:01:08

ArkUI布局渲染
点赞
收藏

51CTO技术栈公众号