【HarmonyOS NEXT】鸿蒙开发:钟表页面

实现效果

绘制钟表

使用 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%')
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值