实现效果
绘制钟表
使用 Circle
绘制了一个圆环作为钟表的边框,通过设置宽度、高度、填充透明度、线条宽度、颜色和虚线样式来呈现特定的效果。
对于时针、分针和秒针,分别使用 Line
元素来绘制。它们的旋转角度根据秒数进行计算,以准确指示时间。时针的颜色为橙色,分针为红色,秒针为黑色,并且分针和秒针还具有线性动画效果,增强了视觉的流畅性。
数字部分通过循环绘制,并根据数字进行相应的旋转和偏移,使数字均匀分布在钟表的周边。
// 钟表的堆叠布局
Stack() {
// 绘制圆环
Circle()
.width(this.radius)
.height(this.radius)
.fillOpacity(0)
.strokeWidth(3)
.stroke(Color.Red)
.strokeDashArray([1, this.radius * Math.PI / 12 - 1])
// 小时指针的线条
Line()
.rotate({
// 旋转中心
centerX: this.radius / 2,
centerY: this.radius / 2,
// 旋转角度根据秒数计算
angle: this.second / 3600 * 30
})
.width(this.radius)
.height(this.radius)
.startPoint([this.radius / 2, this.radius / 2])
.endPoint([this.radius / 2, 60])
.strokeWidth(5)
.stroke(Color.Orange)
.strokeOpacity(0.5)
// 分钟指针的线条
Line()
.rotate({
// 旋转中心
centerX: this.radius / 2,
centerY: this.radius / 2,
// 旋转角度根据秒数计算
angle: this.second / 60 * 6
})
.width(this.radius)
.height(this.radius)
.startPoint([this.radius / 2, this.radius / 2])
.endPoint([this.radius / 2, 40])
.stroke(Color.Red)
.strokeWidth(3)
.animation({
// 线性动画设置
curve: Curve.Linear,
duration: 1000
})
// 秒针指针的线条
Line()
.rotate({
// 旋转中心
centerX: this.radius / 2,
centerY: this.radius / 2,
// 旋转角度根据秒数计算
angle: this.second * 6
})
.width(this.radius)
.height(this.radius)
.startPoint([this.radius / 2, this.radius / 2])
.endPoint([this.radius / 2, 20])
.stroke(Color.Black)
.strokeWidth(2)
.animation({
// 线性动画设置
curve: Curve.Linear,
duration: 1000
})
// 数字部分
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], (item: number) => {
Row() {
Text(item.toString())
.rotate({
// 数字的旋转角度
angle: item * -30
})
.offset({ y: this.radius * -0.55 })
}
.rotate({
// 数字的整体旋转角度
angle: item * 30
})
})
}
// 上下边距设置
.margin({ top: 30, bottom: 30 })
时间选择按钮
当用户点击该按钮时,会弹出一个时间选择对话框 TimePickerDialog
。在对话框的配置中,设置了初始选择的时间、使用 24 小时制、不同状态下的文本样式等。同时,为对话框的接受、取消、改变等操作定义了相应的回调函数,用于处理时间选择的结果和进行相应的状态更新以及日志输出。
Button("TimePickerDialog 24小时制")
.margin(20)
.onClick(() => {
TimePickerDialog.show({
selected: this.selectTime,
useMilitaryTime: true,
disappearTextStyle: { color: Color.Red, font: { size: 15, weight: FontWeight.Lighter } },
textStyle: { color: Color.Black, font: { size: 20, weight: FontWeight.Normal } },
selectedTextStyle: { color: Color.Blue, font: { size: 30, weight: FontWeight.Bolder } },
onAccept: (value: TimePickerResult) => {
if (value.hour!= undefined && value.minute!= undefined) {
console.info("TimePickerDialog:onAccept()" + JSON.stringify(value))
this.second = value.hour * 3600 + value.minute * 60
}
},
onCancel: () => {
console.info("TimePickerDialog:onCancel()")
},
onChange: (value: TimePickerResult) => {
console.info("TimePickerDialog:onChange()" + JSON.stringify(value))
},
onDidAppear: () => {
console.info("TimePickerDialog:onDidAppear()")
},
onDidDisappear: () => {
console.info("TimePickerDialog:onDidDisappear()")
},
onWillAppear: () => {
console.info("TimePickerDialog:onWillAppear()")
},
onWillDisappear: () => {
console.info("TimePickerDialog:onWillDisappear()")
}
})
})
时间获取并且实时流动
使用 @State
装饰器声明了多个状态变量:
@State private selectTime: Date = new Date(systemDateTime.getTime())
@State message: string = 'Hello World';
@State timeoutID: number = 0
@State second: number = 0
@State radius: number = 260
在 aboutToAppear
方法中,根据当前系统时间计算出初始的秒数,并启动每秒递增秒数的定时操作:
aboutToAppear(): void {
this.second = this.selectTime.getHours() * 60 * 60
this.second = this.second + this.selectTime.getMinutes() * 60
this.second = this.second + this.selectTime.getSeconds() + 1
this.timeoutID = setInterval(() => {
this.second++
}, 1000);
}
完整代码
import { curves } from '@kit.ArkUI';
import { systemDateTime } from '@kit.BasicServicesKit';
@Entry
@Component
struct Work3Page {
@State private selectTime: Date = new Date(systemDateTime.getTime())
@State message: string = 'Hello World';
@State timeoutID: number = 0
@State second: number = 0
@State radius: number = 260
aboutToAppear(): void {
this.second = this.selectTime.getHours() * 60 * 60
this.second = this.second + this.selectTime.getMinutes() * 60
this.second = this.second + this.selectTime.getSeconds() + 1
this.timeoutID = setInterval(() => {
this.second++
}, 1000);
}
build() {
Column() {
Column() {
Image($r('app.media.ic_like'))
.width(100)
.aspectRatio(1)
.stateStyles({
normal: {
.translate({ x: 0 })
},
pressed: {
.translate({ y: -100 })
}
})
.animation({
curve: curves.springMotion()
})
.onClick(() => {
this.second += 60
})
//钟表
Stack() {
// 绘制一个直径为150、线条为红色虚线的圆环(宽高设置不一致时以短边为直径)
Circle()
.width(this.radius)
.height(this.radius)
.fillOpacity(0)
.strokeWidth(3)
.stroke(Color.Red)
.strokeDashArray([1, this.radius * Math.PI / 12 - 1])
//时
Line()
.rotate({
centerX: this.radius / 2,
centerY: this.radius / 2,
angle: this.second / 3600 * 30
})
.width(this.radius)
.height(this.radius)
.startPoint([this.radius / 2, this.radius / 2])
.endPoint([this.radius / 2, 60])
.strokeWidth(5)
.stroke(Color.Orange)
.strokeOpacity(0.5)
//分
Line()
.rotate({
centerX: this.radius / 2,
centerY: this.radius / 2,
angle: this.second / 60 * 6
})
.width(this.radius)
.height(this.radius)
.startPoint([this.radius / 2, this.radius / 2])
.endPoint([this.radius / 2, 40])
.stroke(Color.Red)
.strokeWidth(3)
.animation({
curve: Curve.Linear,
duration: 1000
})
//秒
Line()
.rotate({
centerX: this.radius / 2,
centerY: this.radius / 2,
angle: this.second * 6
})
.width(this.radius)
.height(this.radius)
.startPoint([this.radius / 2, this.radius / 2])
.endPoint([this.radius / 2, 20])
.stroke(Color.Black)
.strokeWidth(2)
.animation({
curve: Curve.Linear,
duration: 1000
})
//数字
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], (item: number) => {
Row() {
Text(item.toString())
.rotate({
angle: item * -30
})
.offset({ y: this.radius * -0.55 })
}
.rotate({
angle: item * 30
})
})
}
.margin({ top: 30, bottom: 30 })
Button("TimePickerDialog 24小时制")
.margin(20)
.onClick(() => {
TimePickerDialog.show({
selected: this.selectTime,
useMilitaryTime: true,
disappearTextStyle: { color: Color.Red, font: { size: 15, weight: FontWeight.Lighter } },
textStyle: { color: Color.Black, font: { size: 20, weight: FontWeight.Normal } },
selectedTextStyle: { color: Color.Blue, font: { size: 30, weight: FontWeight.Bolder } },
onAccept: (value: TimePickerResult) => {
if (value.hour != undefined && value.minute != undefined) {
console.info("TimePickerDialog:onAccept()" + JSON.stringify(value))
this.second = value.hour * 3600 + value.minute * 60
}
},
onCancel: () => {
console.info("TimePickerDialog:onCancel()")
},
onChange: (value: TimePickerResult) => {
console.info("TimePickerDialog:onChange()" + JSON.stringify(value))
},
onDidAppear: () => {
console.info("TimePickerDialog:onDidAppear()")
},
onDidDisappear: () => {
console.info("TimePickerDialog:onDidDisappear()")
},
onWillAppear: () => {
console.info("TimePickerDialog:onWillAppear()")
},
onWillDisappear: () => {
console.info("TimePickerDialog:onWillDisappear()")
}
})
})
}
}
.width('100%')
.height('100%')
}
}