简单时钟
介绍
本示例通过使用[@ohos.display]接口以及Canvas组件来实现一个简单的时钟应用。
效果预览
主页 |
---|
使用说明
1.界面通过setInterval实现周期性实时刷新时间,使用Canvas绘制时钟,指针旋转角度通过计算得出。
例如:"2 * Math.PI / 60 * second"是秒针旋转的角度。
鸿蒙开发应用知识已更新gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md
参考前往。
具体实现
鸿蒙学习文档前往mau123789是v添加即可
- 本示例展示简单时钟的方法主要封装在Index中,源码参考:[Index.ets] 。
/** Copyright (c) 2022 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import display from '@ohos.display'import Logger from '../model/Logger'const HOURS: Array<string> = ['3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '1', '2']const HEIGHT_ADD: number = 150 // 表盘下面需要绘制时间,canvas高度是宽度加150const TAG: string = 'Index'@Entry@Componentstruct Clock {private settings: RenderingContextSettings = new RenderingContextSettings(true)private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)@State canvasWidth: number = 300 // 300是表盘默认大小private radius: number = 150 // 默认表盘半径private intervalId: number = 0updateTime = () => {this.context.clearRect(0, 0, this.canvasWidth, this.canvasWidth + HEIGHT_ADD)let nowTime = new Date()let hour = nowTime.getHours()let minute = nowTime.getMinutes()let second = nowTime.getSeconds()let time = `${this.fillTime(hour)}:${this.fillTime(minute)}:${this.fillTime(second)}`this.drawBackGround()this.drawHour(hour, minute)this.drawMinute(minute)this.drawSecond(second)this.drawDot()this.drawTime(time)this.context.translate(-this.radius, -this.radius)}fillTime(time: number) {return time < 10 ? `0${time}` : `${time}`}aboutToAppear() {this.getSize()}// 获取设备宽高计算表盘大小async getSize() {let mDisplay = await display.getDefaultDisplay()Logger.info(TAG, `getDefaultDisplay mDisplay = ${JSON.stringify(mDisplay)}`)this.canvasWidth = px2vp(mDisplay.width > mDisplay.height ? mDisplay.height * 0.6 : mDisplay.width * 0.6)this.radius = this.canvasWidth / 2}drawBackGround() {// 绘制背景let grad = this.context.createRadialGradient(this.radius, this.radius, this.radius - 32, this.radius,this.radius, this.radius)grad.addColorStop(0.0, 'white')grad.addColorStop(0.9, '#eee')grad.addColorStop(1.0, 'white')this.context.fillStyle = gradthis.context.fillRect(0, 0, this.canvasWidth, this.canvasWidth)// 绘制外圈圆this.context.translate(this.radius, this.radius)this.context.lineWidth = 6this.context.beginPath()this.context.strokeStyle = '#fff'this.context.arc(0, 0, this.radius - 5, 0, 2 * Math.PI, false)this.context.stroke()// 绘制时间文字this.context.font = '30px'this.context.textAlign = "center"this.context.textBaseline = "middle"this.context.fillStyle = '#000'this.context.save()HOURS.forEach((num, index) => {let rad = 2 * Math.PI / 12 * indexlet x = Math.cos(rad) * (this.radius - 38)let y = Math.sin(rad) * (this.radius - 38)this.context.fillText(num, x, y)})this.context.restore()// 绘制刻度for (let i = 0; i < 60; i++) {let rad = 2 * Math.PI / 60 * ilet x = Math.cos(rad) * (this.radius - 12)let y = Math.sin(rad) * (this.radius - 12)this.context.beginPath()this.context.moveTo(x, y)if (i % 5 == 0) {let x1 = Math.cos(rad) * (this.radius - 20)let y1 = Math.sin(rad) * (this.radius - 20)this.context.strokeStyle = '#000'this.context.lineWidth = 2this.context.lineTo(x1, y1)} else {let x1 = Math.cos(rad) * (this.radius - 18)let y1 = Math.sin(rad) * (this.radius - 18)this.context.strokeStyle = '#ccc'this.context.lineWidth = 1this.context.lineTo(x1, y1)}this.context.stroke()}this.context.restore()}// 绘制时针drawHour(hour: number, minute: number) {this.context.save()this.context.beginPath()this.context.lineWidth = 8this.context.lineCap = 'round'let rad = 2 * Math.PI / 12 * hourlet mrad = 2 * Math.PI / 12 / 60 * minutethis.context.rotate(rad + mrad)this.context.moveTo(0, 10)this.context.strokeStyle = '#000'this.context.lineTo(0, -this.radius / 2)this.context.stroke()this.context.restore()}// 绘制分针drawMinute(minute: number) {this.context.save()this.context.beginPath()this.context.lineWidth = 5this.context.lineCap = 'round'let rad = 2 * Math.PI / 60 * minutethis.context.rotate(rad)this.context.moveTo(0, 10)this.context.strokeStyle = '#000'this.context.lineTo(0, -this.radius + 40)this.context.stroke()this.context.restore()}// 绘制秒针drawSecond(second: number) {this.context.save()this.context.beginPath()this.context.lineWidth = 2this.context.lineCap = 'round'let rad = 2 * Math.PI / 60 * secondthis.context.rotate(rad)this.context.moveTo(0, 10)this.context.strokeStyle = '#05f'this.context.lineTo(0, -this.radius + 21)this.context.stroke()this.context.restore()}// 绘制中心点drawDot() {this.context.save()this.context.beginPath()this.context.fillStyle = '#05f'this.context.arc(0, 0, 4, 0, 2 * Math.PI, false)this.context.fill()this.context.restore()}// 绘制表盘下面时间文本drawTime(time: string) {this.context.save()this.context.beginPath()this.context.font = '90px'this.context.textAlign = "center"this.context.textBaseline = "middle"this.context.fillStyle = '#000'this.context.fillText(time, 0, this.radius + 80)this.context.restore()}build() {Stack({ alignContent: Alignment.Center }) {Canvas(this.context).padding({ top: 76 }).width(this.canvasWidth).height(this.canvasWidth + HEIGHT_ADD).onReady(() => {this.updateTime()this.intervalId = setInterval(this.updateTime, 1000)})}.width('100%').height('100%')}onPageHide() {clearInterval(this.intervalId)}aboutToDisappear(){clearInterval(this.intervalId)}}
- 设置表盘大小:通过Index中的display.getDefaultDisplay()方法来获取设备宽高计算表盘大小;
- 获取当前时间:调用updateTime函数,执行new Date().getHours()、new Date().getMinutes()、new Date().getSeconds()获取当前时间。
- 绘制表盘内容:通过[CanvasRenderingContext2D] 来画表盘背景、时针、分针、秒针、圆心以及表盘下方文本;
- 启动时钟:添加setInterval定时器,每隔1s执行一次updateTime函数。