当前位置: 首页 > news >正文

鸿蒙简易时钟应用

代码功能概述

这段代码实现了一个功能完整的鸿蒙时钟应用,全面展示了ArkTS在时间处理、多时区显示、闹钟设置和界面动画等方面的核心能力。主要功能包括:

  • 模拟时钟:显示带有时针、分针、秒针的模拟时钟

  • 数字时钟:显示精确到秒的数字时间

  • 多时区支持:显示不同时区的当前时间

  • 闹钟功能:设置和管理多个闹钟

  • 倒计时器:支持自定义时间的倒计时功能

  • 世界时钟:同时显示多个主要城市的时间

  • 时间设置:模拟调整系统时间

通过这个示例,可以深入理解ArkTS如何实现时间处理、动画效果和复杂的状态管理。

2. 代码逻辑分析

应用采用"时间驱动UI"的架构设计:

  1. 初始化阶段:应用启动时,初始化时间数据和多时区信息

  2. 状态管理:使用多个@State装饰器管理当前时间、时区、闹钟列表和倒计时状态

  3. 实时更新时间

    • 使用定时器每秒更新当前时间 → 刷新数字显示和模拟时钟指针

    • 多时区计算 → 根据时区偏移计算各城市时间 → 更新显示

  4. 闹钟管理

    • 添加闹钟 → 设置时间、重复规则 → 添加到闹钟列表

    • 启用/禁用闹钟 → 切换闹钟状态 → 更新界面

    • 闹钟触发 → 检查当前时间 → 显示提醒(模拟)

  5. 倒计时功能

    • 设置倒计时时间 → 启动倒计时 → 每秒更新剩余时间

    • 倒计时结束 → 触发提醒 → 重置状态

  6. 界面动画

    • 模拟时钟指针的平滑转动动画

    • 界面切换的过渡效果

完整代码

@Entry @Component struct ClockTutorial { @State currentTime: Date = new Date(); @State selectedTimezone: string = 'Asia/Shanghai'; @State isAnalogMode: boolean = true; @State alarms: Alarm[] = []; @State countdownTime: number = 0; @State isCountingDown: boolean = false; @State worldClocks: WorldClock[] = [ { city: '北京', timezone: 'Asia/Shanghai', time: '' }, { city: '纽约', timezone: 'America/New_York', time: '' }, { city: '伦敦', timezone: 'Europe/London', time: '' }, { city: '东京', timezone: 'Asia/Tokyo', time: '' } ]; aboutToAppear() { this.startClock(); this.loadSampleAlarms(); } build() { Column({ space: 0 }) { // 模式切换 this.BuildModeToggle() // 时钟显示区域 if (this.isAnalogMode) { this.BuildAnalogClock() } else { this.BuildDigitalClock() } // 世界时钟 this.BuildWorldClocks() // 功能按钮 this.BuildFunctionButtons() // 闹钟列表 this.BuildAlarmList() } .width('100%') .height('100%') .padding(20) .backgroundColor('#1A1A2E') } @Builder BuildModeToggle() { Row({ space: 20 }) { Button('模拟时钟') .onClick(() => { this.isAnalogMode = true; }) .backgroundColor(this.isAnalogMode ? '#4A90E2' : '#2D3748') .fontColor('#FFFFFF') .borderRadius(20) .padding({ left: 20, right: 20 }) .height(40) Button('数字时钟') .onClick(() => { this.isAnalogMode = false; }) .backgroundColor(!this.isAnalogMode ? '#4A90E2' : '#2D3748') .fontColor('#FFFFFF') .borderRadius(20) .padding({ left: 20, right: 20 }) .height(40) } .width('100%') .justifyContent(FlexAlign.Center) .margin({ bottom: 20 }) } @Builder BuildAnalogClock() { const hours = this.currentTime.getHours() % 12; const minutes = this.currentTime.getMinutes(); const seconds = this.currentTime.getSeconds(); Stack({ alignContent: Alignment.Center }) { // 时钟外圈 Circle({ width: 280, height: 280 }) .fill('#0F3460') .stroke('#4A90E2') .strokeWidth(4) // 时钟刻度 ForEach(Array.from({ length: 12 }), (_, index: number) => { const angle = (index * 30) * Math.PI / 180; const x1 = 140 + 120 * Math.sin(angle); const y1 = 140 - 120 * Math.cos(angle); const x2 = 140 + 130 * Math.sin(angle); const y2 = 140 - 130 * Math.cos(angle); Line() .startPoint({ x: x1, y: y1 }) .endPoint({ x: x2, y: y2 }) .strokeWidth(2) .strokeColor('#FFFFFF') }) // 时针 Line() .startPoint({ x: 140, y: 140 }) .endPoint({ x: 140 + 60 * Math.sin((hours * 30 + minutes * 0.5) * Math.PI / 180), y: 140 - 60 * Math.cos((hours * 30 + minutes * 0.5) * Math.PI / 180) }) .strokeWidth(6) .strokeColor('#FFFFFF') .lineCap(LineCapStyle.Round) // 分针 Line() .startPoint({ x: 140, y: 140 }) .endPoint({ x: 140 + 80 * Math.sin(minutes * 6 * Math.PI / 180), y: 140 - 80 * Math.cos(minutes * 6 * Math.PI / 180) }) .strokeWidth(4) .strokeColor('#4A90E2') .lineCap(LineCapStyle.Round) // 秒针 Line() .startPoint({ x: 140, y: 140 }) .endPoint({ x: 140 + 90 * Math.sin(seconds * 6 * Math.PI / 180), y: 140 - 90 * Math.cos(seconds * 6 * Math.PI / 180) }) .strokeWidth(2) .strokeColor('#FF6B6B') .lineCap(LineCapStyle.Round) // 中心点 Circle({ width: 12, height: 12 }) .fill('#FF6B6B') } .width(280) .height(280) .margin({ bottom: 20 }) } @Builder BuildDigitalClock() { Column({ space: 10 }) { Text(this.formatTime(this.currentTime)) .fontSize(64) .fontWeight(FontWeight.Bold) .fontColor('#FFFFFF') Text(this.formatDate(this.currentTime)) .fontSize(18) .fontColor('#A0AEC0') Text(this.getWeekday(this.currentTime)) .fontSize(16) .fontColor('#4A90E2') } .width('100%') .height(160) .justifyContent(FlexAlign.Center) .margin({ bottom: 20 }) } @Builder BuildWorldClocks() { Column({ space: 10 }) { Text('世界时间') .fontSize(18) .fontWeight(FontWeight.Medium) .fontColor('#FFFFFF') .alignSelf(ItemAlign.Start) .margin({ bottom: 10 }) Grid() { ForEach(this.worldClocks, (clock: WorldClock) => { GridItem() { this.BuildWorldClockItem(clock) } }) } .columnsTemplate('1fr 1fr') .rowsTemplate('1fr 1fr') .columnsGap(15) .rowsGap(15) .width('100%') } .width('100%') .margin({ bottom: 20 }) } @Builder BuildWorldClockItem(clock: WorldClock) { Column({ space: 8 }) { Text(clock.city) .fontSize(16) .fontWeight(FontWeight.Medium) .fontColor('#FFFFFF') .alignSelf(ItemAlign.Start) Text(clock.time) .fontSize(14) .fontColor('#A0AEC0') .alignSelf(ItemAlign.Start) Text(clock.timezone) .fontSize(12) .fontColor('#4A90E2') .alignSelf(ItemAlign.Start) } .width('100%') .height(80) .padding(12) .backgroundColor('#2D3748') .borderRadius(12) } @Builder BuildFunctionButtons() { Row({ space: 15 }) { Button('闹钟') .onClick(() => { this.showAlarmDialog(); }) .backgroundColor('#4A90E2') .fontColor('#FFFFFF') .borderRadius(12) .layoutWeight(1) .height(50) Button('倒计时') .onClick(() => { this.startCountdown(300); // 5分钟倒计时 }) .backgroundColor(this.isCountingDown ? '#FF6B6B' : '#2D3748') .fontColor('#FFFFFF') .borderRadius(12) .layoutWeight(1) .height(50) Button('秒表') .onClick(() => { this.startStopwatch(); }) .backgroundColor('#2D3748') .fontColor('#FFFFFF') .borderRadius(12) .layoutWeight(1) .height(50) } .width('100%') .margin({ bottom: 20 }) } @Builder BuildAlarmList() { Column({ space: 10 }) { Row({ space: 10 }) { Text('闹钟') .fontSize(18) .fontWeight(FontWeight.Medium) .fontColor('#FFFFFF') .layoutWeight(1) Text(`${this.alarms.length} 个`) .fontSize(14) .fontColor('#A0AEC0') } .width('100%') if (this.alarms.length === 0) { this.BuildEmptyState('暂无闹钟', '点击上方"闹钟"按钮添加') } else { ForEach(this.alarms.slice(0, 3), (alarm: Alarm) => { this.BuildAlarmItem(alarm) }) } } .width('100%') } @Builder BuildAlarmItem(alarm: Alarm) { Row({ space: 15 }) { Column({ space: 5 }) { Text(this.formatAlarmTime(alarm.hour, alarm.minute)) .fontSize(20) .fontWeight(FontWeight.Bold) .fontColor('#FFFFFF') .alignSelf(ItemAlign.Start) Text(this.getAlarmDays(alarm.days)) .fontSize(12) .fontColor('#A0AEC0') .alignSelf(ItemAlign.Start) } .layoutWeight(1) Toggle({ type: ToggleType.Switch, isOn: alarm.enabled }) .onChange((value: boolean) => { alarm.enabled = value; }) .width(40) Button('删除') .onClick(() => { this.deleteAlarm(alarm.id); }) .backgroundColor('transparent') .fontColor('#FF6B6B') .fontSize(12) .padding(8) } .width('100%') .padding(15) .backgroundColor('#2D3748') .borderRadius(12) .margin({ bottom: 10 }) } @Builder BuildEmptyState(title: string, message: string) { Column({ space: 10 }) { Text('⏰') .fontSize(32) .opacity(0.5) Text(title) .fontSize(16) .fontColor('#A0AEC0') Text(message) .fontSize(14) .fontColor('#718096') } .width('100%') .height(100) .justifyContent(FlexAlign.Center) .backgroundColor('#2D3748') .borderRadius(12) } private startClock(): void { // 更新时间 setInterval(() => { this.currentTime = new Date(); this.updateWorldClocks(); this.checkAlarms(); if (this.isCountingDown && this.countdownTime > 0) { this.countdownTime--; if (this.countdownTime === 0) { this.countdownComplete(); } } }, 1000); } private updateWorldClocks(): void { const now = this.currentTime; this.worldClocks.forEach(clock => { const offset = this.getTimezoneOffset(clock.timezone); const cityTime = new Date(now.getTime() + offset * 60 * 60 * 1000); clock.time = this.formatTime(cityTime); }); } private getTimezoneOffset(timezone: string): number { // 简化的时区偏移计算 const offsets: { [key: string]: number } = { 'Asia/Shanghai': 8, 'America/New_York': -5, 'Europe/London': 0, 'Asia/Tokyo': 9 }; return offsets[timezone] || 0; } private formatTime(date: Date): string { const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); const seconds = date.getSeconds().toString().padStart(2, '0'); return `${hours}:${minutes}:${seconds}`; } private formatDate(date: Date): string { const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); return `${year}-${month}-${day}`; } private getWeekday(date: Date): string { const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; return weekdays[date.getDay()]; } private loadSampleAlarms(): void { this.alarms = [ { id: '1', hour: 7, minute: 30, days: [1, 2, 3, 4, 5], enabled: true }, { id: '2', hour: 9, minute: 0, days: [0, 6], enabled: false }, { id: '3', hour: 22, minute: 0, days: [0, 1, 2, 3, 4, 5, 6], enabled: true } ]; } private formatAlarmTime(hour: number, minute: number): string { return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`; } private getAlarmDays(days: number[]): string { if (days.length === 7) return '每天'; if (days.length === 5 && !days.includes(0) && !days.includes(6)) return '工作日'; if (days.length === 2 && days.includes(0) && days.includes(6)) return '周末'; const dayNames = ['日', '一', '二', '三', '四', '五', '六']; return days.map(day => dayNames[day]).join(', '); } private showAlarmDialog(): void { // 模拟显示闹钟设置对话框 console.log('显示闹钟设置对话框'); // 这里可以添加新的闹钟 const newAlarm: Alarm = { id: Date.now().toString(), hour: 8, minute: 0, days: [1, 2, 3, 4, 5], enabled: true }; this.alarms.push(newAlarm); } private deleteAlarm(id: string): void { this.alarms = this.alarms.filter(alarm => alarm.id !== id); } private startCountdown(seconds: number): void { if (this.isCountingDown) { this.isCountingDown = false; this.countdownTime = 0; } else { this.isCountingDown = true; this.countdownTime = seconds; } } private countdownComplete(): void { this.isCountingDown = false; // 模拟倒计时完成提醒 console.log('倒计时完成!'); } private startStopwatch(): void { // 模拟秒表功能 console.log('启动秒表'); } private checkAlarms(): void { const now = this.currentTime; const currentHour = now.getHours(); const currentMinute = now.getMinutes(); const currentDay = now.getDay(); this.alarms.forEach(alarm => { if (alarm.enabled && alarm.hour === currentHour && alarm.minute === currentMinute && alarm.days.includes(currentDay)) { this.triggerAlarm(alarm); } }); } private triggerAlarm(alarm: Alarm): void { // 模拟闹钟触发 console.log(`闹钟触发: ${this.formatAlarmTime(alarm.hour, alarm.minute)}`); // 这里可以添加声音或震动提醒 } } class Alarm { id: string = ''; hour: number = 0; minute: number = 0; days: number[] = []; enabled: boolean = true; } class WorldClock { city: string = ''; timezone: string = ''; time: string = ''; }

想入门鸿蒙开发又怕花冤枉钱?别错过!现在能免费系统学 -- 从 ArkTS 面向对象核心的类和对象、继承多态,到吃透鸿蒙开发关键技能,还能冲刺鸿蒙基础 +高级开发者证书,更惊喜的是考证成功还送好礼!快加入我的鸿蒙班,一起从入门到精通,班级链接:点击https://developer.huawei.com/consumer/cn/training/classDetail/b7365031334e4353a9a0fd6785bb0791?type=1?ha_source=hmosclass&ha_sourceId=89000248免费进入

http://www.cnnetsun.cn/news/1338.html

相关文章:

  • 大模型在手术操作后呼吸衰竭预测及围手术期方案制定中的应用研究
  • 大模型在金黄色葡萄球菌性败血症预测及围手术期管理中的应用研究
  • (附源码)基于Web的高校体育成绩管理系统设计与实现-计算机毕设 30378
  • android开发 拆分包APK的安装方式
  • Java Lambda stream reduce
  • Java入门篇,小白有任何不懂的,收藏这篇就够了
  • 对象失业半年多了,Java程序员,IT行业是不是再也找不到工作了
  • Java集合框架全面详解,从小白到精通,收藏这篇就够了
  • 探索Java设计模式:原理、应用与实践,小白到精通,收藏这篇就足够了
  • JavaWeb后端阶段项目,从小白到高级开发,收藏这篇就足够了
  • python运维自动化脚本案例,python自动化运维工具,收藏这篇就够了
  • kafka运维命令大全,零基础入门到精通,收藏这篇就够了
  • 运维简历包装,零基础入门到精通,收藏这篇就够了
  • 服务器SSH没有问题,但是VNC连接失败解决方法,收藏这篇就够了
  • 企业平台化运维能力养成记,零基础入门到精通,收藏这篇就够了
  • mysql日常运维与参数调优,零基础入门到精通,收藏这篇就够了
  • 43岁年纪的系统运维裁员后还能找到运维岗位吗?
  • 37岁前端被裁,深夜刷招聘软件的手都在抖
  • 【Paper2Slides】1:提示词分析:图片生成、内容规划、论文提取
  • 【Paper2Slides】2:图片生成工作逻辑
  • 能用自然语言透明地解释每一步的推理过程‌,彻底打破了传统AI的“黑盒”模式的围棋AI大模型:InternThinke
  • 32 FSMC
  • 单细胞转录组分析流程十一(细胞通讯,cellchat,多个不同细胞的样本)
  • CellChat 原理介绍:从单细胞数据推断细胞通讯的科学方法
  • 最全的ansible自动化运维问题查询指南,零基础入门到精通,收藏这篇就够了
  • 网络运维工程师面试(笔试),零基础入门到精通,收藏这篇就够了
  • mysql 8.0运维与优化,零基础入门到精通,收藏这篇就够了
  • 智能系统运维及常见智能运维系统介绍,零基础入门到精通,收藏这篇就够了
  • Spring Cloud微服务工具集,零基础入门到精通,收藏这篇就够了
  • 对IDC(数据中心)运维了解,零基础入门到精通,收藏这篇就够了