代码功能概述
这段代码实现了一个功能完整的鸿蒙时钟应用,全面展示了ArkTS在时间处理、多时区显示、闹钟设置和界面动画等方面的核心能力。主要功能包括:
-
模拟时钟:显示带有时针、分针、秒针的模拟时钟
-
数字时钟:显示精确到秒的数字时间
-
多时区支持:显示不同时区的当前时间
-
闹钟功能:设置和管理多个闹钟
-
倒计时器:支持自定义时间的倒计时功能
-
世界时钟:同时显示多个主要城市的时间
-
时间设置:模拟调整系统时间
通过这个示例,可以深入理解ArkTS如何实现时间处理、动画效果和复杂的状态管理。
2. 代码逻辑分析
应用采用"时间驱动UI"的架构设计:
-
初始化阶段:应用启动时,初始化时间数据和多时区信息
-
状态管理 :使用多个
@State装饰器管理当前时间、时区、闹钟列表和倒计时状态 -
实时更新时间:
-
使用定时器每秒更新当前时间 → 刷新数字显示和模拟时钟指针
-
多时区计算 → 根据时区偏移计算各城市时间 → 更新显示
-
-
闹钟管理:
-
添加闹钟 → 设置时间、重复规则 → 添加到闹钟列表
-
启用/禁用闹钟 → 切换闹钟状态 → 更新界面
-
闹钟触发 → 检查当前时间 → 显示提醒(模拟)
-
-
倒计时功能:
-
设置倒计时时间 → 启动倒计时 → 每秒更新剩余时间
-
倒计时结束 → 触发提醒 → 重置状态
-
-
界面动画:
-
模拟时钟指针的平滑转动动画
-
界面切换的过渡效果
-
完整代码
@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免费进入