鸿蒙HarmonyOS开发实例:【简单时钟】

简单时钟

介绍

本示例通过使用[@ohos.display]接口以及Canvas组件来实现一个简单的时钟应用。

效果预览

主页
main

使用说明

1.界面通过setInterval实现周期性实时刷新时间,使用Canvas绘制时钟,指针旋转角度通过计算得出。

例如:"2 * Math.PI / 60 * second"是秒针旋转的角度。

鸿蒙开发应用知识已更新gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md参考前往。

搜狗高速浏览器截图20240326151547.png

具体实现

鸿蒙学习文档前往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高度是宽度加150

const TAG: string = 'Index'



@Entry

@Component

struct 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 = 0

  updateTime = () => {

    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 = grad

    this.context.fillRect(0, 0, this.canvasWidth, this.canvasWidth)



    // 绘制外圈圆

    this.context.translate(this.radius, this.radius)

    this.context.lineWidth = 6

    this.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 * index

      let 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 * i

      let 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 = 2

        this.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 = 1

        this.context.lineTo(x1, y1)

      }

      this.context.stroke()

    }

    this.context.restore()

  }



  // 绘制时针

  drawHour(hour: number, minute: number) {

    this.context.save()

    this.context.beginPath()

    this.context.lineWidth = 8

    this.context.lineCap = 'round'

    let rad = 2 * Math.PI / 12 * hour

    let mrad = 2 * Math.PI / 12 / 60 * minute

    this.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 = 5

    this.context.lineCap = 'round'

    let rad = 2 * Math.PI / 60 * minute

    this.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 = 2

    this.context.lineCap = 'round'

    let rad = 2 * Math.PI / 60 * second

    this.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函数。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

三角测量法恢复深度

参考&#xff1a;单目vo中的深度确定方法--三角测量_单目相机三角测量-CSDN博客 方法一&#xff1a;直接法 由于我们已经通过本质矩阵分解或者单应矩阵分解获得了R与t&#xff0c;此时想求的是两个特征点的深度 bool depthFromTriangulation(const SE3& T_search_ref,co…

电脑打开游戏的时候提示缺少.dll文件?照着这个来就行。

前言 小白曾经也是一个很喜欢玩游戏的人&#xff0c;但那只是曾经。那时候宿舍里一共6个人&#xff0c;都是比较喜欢玩游戏的小伙子。 话题好像偏了…… 有些小伙伴下载玩游戏之后&#xff0c;高高兴兴地想要开始玩。结果游戏根本没办法运行&#xff0c;可恶&#xff01;这该…

美国P6139B泰克无源探头

181/2461/8938产品概述&#xff1a; 500 MHz探头带宽探针尖端的大输入阻抗为10兆欧&#xff0c;8 pF补偿范围:8 pF至18 pF电缆长度:1.3米10倍衰减系数300 V CAT II输入电压用于探测小几何形状电路元件的紧凑探头小探针体增强了被测设备的可视性可更换探针头盒大型配件套装&…

《QT实用小工具·二十一》鼠标十字线

1、概述 源码放在文章末尾 该项目实现了界面绘制十字线并跟随鼠标移动的过程&#xff0c;下面是demo演示&#xff1a; 项目部分代码如下&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget>namespace Ui { class Widget; }class Widget : public QWidg…

Bioorganic Chemistry:中国药科大学王鹏课题组、陈俊青课题组设计的基于AIE机理的高荧光选择性鉴定Cys/HCy

文献来源&#xff1a;Highly selective fluorescent probe based on AIE for identifying cysteine/homocysteine - PubMed (nih.gov) 一、AIE机理在荧光探针设计方向的应用&#xff1a; 参考文献&#xff1a;几种代表性的AIE的发光特点和机制&#xff08;2020-10-11&#xff…

基于数据沙箱与LLM用例自愈的UI自动化测试平台

UI自动化测试能够在一定程度上确保产品质量&#xff0c;尤其在降本提效的大背景下&#xff0c;其重要性愈发凸显。理想情况下&#xff0c;UI自动化测试不仅能够能帮我们规避不少线上问题&#xff0c;又能加快产品上线速度。然而现实却往往相去甚远&#xff0c;在多数情况下&…

移动端WEB开发之响应式布局

一、响应式开发 1.1 响应式开发原理 就是使用媒体查询针对不同宽度的设备进行布局和样式的设置&#xff0c;从而适配不同设备的目的。 1.2 响应式布局容器 响应式需要一个父级做为布局容器&#xff0c;来配合子级元素来实现变化效果。原理就是在不同屏幕下&#xff0c;通过媒体…

HJ37 统计每个月兔子的总数(动态规划)

高端的食材&#xff0c;往往只需要最简单的烹饪方法。 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的…

sql注入之堆叠和二次注入

1.1 堆叠注入原理 堆叠注入&#xff08;Stacked Injection&#xff09;是一种SQL注入技术&#xff0c;它允许攻击者一次性执行多条SQL语句。其原理主要是利用Web应用程序中的输入验证不严格&#xff0c;通过在输入字段中插入分号&#xff08;;&#xff09;来分隔并构造新的SQL…

【C++ STL有序关联容器】map 映射

文章目录 【 1. 基本原理 】【 2. map 的创建 】2.1 调用默认构造函数&#xff0c;创建一个空的 map2.2 map 被构造的同时初始化2.3 通过一个 map 初始化另一个 map2.4 取已建 map 中指定区域内的键值对&#xff0c;初始化新的 map2.5 指定排序规则 【 2. map 元素的操作 】实例…

最大食物链计数【拓扑排序】

P4017 最大食物链计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<iostream> #include <algorithm> #include <vector> #include <queue> using namespace std; #define int long long const int N2e5100; const int mod80112002; int n,…

小米汽车:搅动市场的鲶鱼or价格战砧板上的鱼肉?

3月28日晚&#xff0c;备受关注的小米汽车上市发布会召开&#xff0c;小米集团董事长雷军宣布小米SU7正式发布。小米汽车在带飞股价的同时&#xff0c;二轮订购迅速售尽。 图一&#xff1a;小米集团股价 雷军口中“小米汽车迈出的第一步&#xff0c;也是人生最后一战的开篇”&a…

如何用微信云开发制作一款商城小程序

微信云开发提供了一整套开发小程序的服务&#xff0c;包括数据库、存储、云函数等&#xff0c;可以帮助商家快速搭建小程序&#xff0c;降低开发成本&#xff0c;提高开发效率。下面&#xff0c;我们将探讨如何使用微信云开发来开发一款商城小程序。 一、注册小程序账号 可以…

三小时使用鸿蒙OS模仿羊了个羊,附源码

学习鸿蒙arkTS语言&#xff0c;决定直接通过实践的方式上手&#xff0c;而不是一点点进行观看视频再来实现。 结合羊了个羊的开发思路&#xff0c;准备好相应的卡片素材后进行开发。遇到了需要arkTS进行解决的问题&#xff0c;再去查看相应的文档。 首先需要准备卡片对应的图片…

swampCTF 2024

swampCTF 2024 MISC Discord Challenge swampCTF{w3lc0m3_t0_th3_swamp} What the Form google form不停重定向&#xff0c;直接F12看一下。flag就在前端。 swampCTF{F0rm5_K33p5_D4T4_H1dd3n} OSINT Lost in Space 图片是旅行者2号&#xff0c;问距离地球多少个天文单…

Games101-光线追踪(基本原理)

光线追踪和光栅化是两个不同的成像方式。 光栅化最大的问题是无法很好的表示全局的效果。 全局效果包括 软阴影(shadow mapping后来被改进成能够支持软阴影&#xff0c;阴影随着离物体越远越来越模糊)&#xff0c;glossy反射(类似镜子&#xff0c;但没有镜子那么光滑&#xff0…

蓝桥杯2023年第十四届省赛真题-棋盘

solution1(暴力) 暴力蓝桥杯可以过&#xff0c;虽然理论上会超时~ #include<iostream> using namespace std; const int maxn 2010; int a[maxn][maxn] {0};//0白棋&#xff0c;1黑棋 int main(){int n, m, x1, x2, y1, y2;scanf("%d%d", &n, &m)…

基于单片机水塔水位检测控制系统设计

**单片机设计介绍&#xff0c; 基于单片机水塔水位检测控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机水塔水位检测控制系统设计的主要目标是实现水塔水位的自动监测与控制&#xff0c;确保水塔内的水位始…

代码随想录第35天| 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球

860.柠檬水找零 860. 柠檬水找零 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 贪心算法&#xff0c;看上去复杂&#xff0c;其实逻辑都是固定的&#xff01;LeetCode&#xff1a;860.柠檬水找零_哔哩哔哩_bilibili 在柠檬水摊上&#xff0c;每…

如何在 iOS 项目中集成 MiniApp SDK,快速构建智能小程序?

本文介绍如何在 iOS 项目中&#xff0c;集成 MiniApp SDK&#xff0c;使之能够构建智能生活小程序&#xff0c;运行在你的 IoT App 上。 准备工作 在集成 MiniApp SDK 之前&#xff0c;您需要在 涂鸦 IoT 开发平台 上&#xff1a; 注册开发者账号、创建产品、创建功能点等。…